spring security入门
1. Restful API和传统API的区别
- 用URL描述资源
- 用http描述方法行为,用http状态码描述结果
- 使用json交互数据
- RESTful是一种风格,不是强制的标准
2. 使用spring mvc开发Restful API
2.1 请求参数校验
1)实体类
import com.fasterxml.jackson.annotation.JsonView;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range; import javax.validation.constraints.NotNull;
import java.util.Date; public class User {
public interface UserSimpleView{}
public interface UserDetailView extends UserSimpleView{} @JsonView(UserSimpleView.class)
private Integer id; @JsonView(UserSimpleView.class)
@NotBlank
private String username; @JsonView(UserDetailView.class)
private String password; @JsonView(UserSimpleView.class)
@Range(max = 200, min = 0)
@NotNull
private Integer age; @JsonView(UserSimpleView.class)
private Date birthday;
}
User.java
2)控制器,如果不加BindingResult参数,并且出异常则不进入方法,直接将错误信息返回
@PostMapping
public User create(@Valid @RequestBody User user, BindingResult errors) {
if (errors.hasErrors()) {
errors.getAllErrors().forEach(error -> {
System.out.println("error ==> "+error.getDefaultMessage());
});
} System.out.println(user);
user.setBirthday(new Date());
return user;
}
2.2 选择性的返回实体类的属性,JsonView
1)实体类
public class User {
public interface UserSimpleView{}
public interface UserDetailView extends UserSimpleView{} @JsonView(UserSimpleView.class)
private Integer id; @JsonView(UserSimpleView.class)
@NotBlank
private String username; @JsonView(UserDetailView.class)
private String password; @JsonView(UserSimpleView.class)
@Range(max = 200, min = 0)
@NotNull
private Integer age; @JsonView(UserSimpleView.class)
private Date birthday;
}
User.java
2)控制器
@GetMapping
@JsonView(User.UserSimpleView.class)
public List<User> query(UserQueryCondition condition,
@PageableDefault(page = 1, size = 10, sort = "age") Pageable pageable) {
System.out.println(condition);
List<User> users = new ArrayList<>();
users.add(new User() {{
setId(1);
setUsername("admin1");
setPassword("123");
setAge(20);
}});
users.add(new User() {{
setId(2);
setUsername("admin2");
setPassword("123");
setAge(22);
}});
return users;
}
UserController.java
2.3 请求URL参数变量
使用正则表达式对请求URL参数做限制
@GetMapping("/{id:\\d+}")
2.2 服务异常处理
在controller中发生异常,怎样处理?
1)自定义异常类
public class UserNotExistException extends RuntimeException {
private static final long serialVersionId = Long.MIN_VALUE; private int id; public UserNotExistException(int id){
super("user not exists");
this.id = id;
}
}
2)处理控制器抛出的异常
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(UserNotExistException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, Object> handlerUserNotExistException(UserNotExistException ex){
Map<String, Object> result = new HashMap<>();
result.put("id", ex.getId());
result.put("message", ex.getMessage());
return result;
}
}
3 RESTful API拦截
3.1 过滤器(Filter)
定义过滤器,注册为spring组件
import javax.servlet.*;
import java.io.IOException;
import java.util.Date; @Component // 让过滤器生效, 默认拦截所有请求(/*)
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("time filter init...");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("time filter start");
long start = new Date().getTime();
filterChain.doFilter(servletRequest, servletResponse);
long finish = new Date().getTime();
System.out.println("time filter 耗时:"+(finish-start));
System.out.println("time filter finish");
} @Override
public void destroy() {
System.out.println("time filter destroy...");
}
}
TimeFilter.java
将第三方过滤器(没有@Component)注册到项目中,将TimeFilter的@Component去掉:
@Configuration
public class WebConfig { @Bean
public FilterRegistrationBean timeFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
registrationBean.setFilter(timeFilter); // 配置拦截的URL
List<String> urls = new ArrayList<>();
urls.add("/*");
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
在过滤器中无法获取控制器中的信息,可以使用拦截器获取spring中的控制器信息
3.2 拦截器(Interceptor)
定义拦截器:
@Component
public class TimeInterceptor implements HandlerInterceptor { // 控制器方法被调用之前
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("prehandler...");
System.out.println(((HandlerMethod)o).getBean().getClass().getName());//o为控制器方法
System.out.println(((HandlerMethod)o).getMethod().getName());//o为控制器方法
return true;
} // 控制器方法被调用之后,如果控制器中抛出异常,则不会调用该方法
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandler..."); } // 处理请求后调用该方法,无论控制器方法是否抛出异常
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("after completion...");
}
}
TimeInterceptor.java
如果配置了控制器异常处理,那么拦截器的异常对象为空。
配置拦截器:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private TimeInterceptor timeInterceptor; @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
3.3 切片(Aspect)
只需定义切面,不需要其他配置即可生效
//比较细粒度的切片,一定能获取到切入点方法的参数信息
@Aspect
@Component
public class TimeAspect {
//切入点定义
@Pointcut("execution(* com.getword.web.controller.UserController.*(..))")
public void myPointcut(){} @Around("myPointcut()")
public Object handlerControllerMethod(ProceedingJoinPoint pjp) throws Throwable { // 参数pjp包含控制器方法信息
System.out.println("time aspect start...");
//获取控制器方法的参数
Object[] args = pjp.getArgs();
for(Object arg : args){
System.out.println("arg is :"+arg);
}
Object object = pjp.proceed();
System.out.println("time aspect finish...");
return object;
}
}
4 文件上传下载
@RestController
@RequestMapping("/file")
public class FileController {
@PostMapping
public FileInfo upload(MultipartFile file){
System.out.println(file.getName());
System.out.println(file.getOriginalFilename());
System.out.println(file.getSize());
try {
InputStream inputStream = file.getInputStream();
file.transferTo(new File(""));
} catch (IOException e) {
e.printStackTrace();
}
FileInfo fileInfo = new FileInfo("");
return fileInfo;
} @GetMapping("/{id}")
public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取file文件
try(InputStream inputStream = new FileInputStream(new File(""));
OutputStream out = response.getOutputStream();
){
response.setContentType("application/x-download");
response.setHeader("Content-Disposition","attachment;filename=test.txt");
IOUtils.copy(inputStream, out);
out.flush();
}
}
}
5 使用多线程提高RESTful性能
5.1 使用Callable,Runnable
@RequestMapping("/order")
public Callable<String> orderAsync(){
logger.info("主线程开始...");
Callable<String> result = new Callable<String>() {
@Override
public String call() throws Exception {
logger.info("副线程开始。。。");
Thread.sleep(1000);
logger.info("副线程返回。。。");
return "success";
}
};
logger.info("主线程返回...");
return result;
}
5.2 异步处理RESTful服务,DeferredResult
1)控制器
@RequestMapping("/order3")
public DeferredResult<String> deferredResult(){
logger.info("主线程开始");
// 生成订单号,相当于线程号
String orderNumber = RandomStringUtils.randomNumeric(8);
// 处理订单,开启新的线程,同时监听是否处理完毕,如果处理完毕就对客户端响应
mockQueue.setPlaceOrder(orderNumber); // 该对象可以完成向 对应客户端 做出响应
DeferredResult<String> deferredResult = new DeferredResult<>();
deferredResultHolder.getMap().put(orderNumber, deferredResult); System.out.println("主线程返回");
return deferredResult;
}
2)订单队列
@Component
public class MockQueue {
private Logger logger = LoggerFactory.getLogger(getClass());
private String placeOrder;
private String completeOrder; public String getPlaceOrder() {
return placeOrder;
} public void setPlaceOrder(String placeOrder) {
// 处理订单业务
new Thread(()->{
logger.info("接到下单请求..."+placeOrder);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.placeOrder = placeOrder;
this.completeOrder = placeOrder;
logger.info("下单请求处理完毕..."+placeOrder);
}).start();
} public String getCompleteOrder() {
return completeOrder;
} public void setCompleteOrder(String completeOrder) {
this.completeOrder = completeOrder;
}
}
MockQueue.java
3)DeferredResultHolder存放<订单序号,DeferredResult>键值对
@Component
public class DeferredResultHolder {
// 订单号,订单结果
private Map<String, DeferredResult<String>> map = new HashMap<>(); public Map<String, DeferredResult<String>> getMap() {
return map;
}
public void setMap(Map<String, DeferredResult<String>> map) {
this.map = map;
}
}
4)订单完成监听器
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
// 开启新的线程监听队列中是否有完成的订单
new Thread(()->{
while (true) {
if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
// 监听到有订单完成了,结束异步请求,返回结果
String orderNumber = mockQueue.getCompleteOrder();
logger.info("返回订单处理结果:" + orderNumber);
deferredResultHolder.getMap().get(orderNumber).setResult("order completed success...");
mockQueue.setCompleteOrder(null);
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
QueueListener.java
6 与前端并行开发
6.1 使用swagger自动生成HTML文档
1)引入maven依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2)在spring boot启动类添加模块
@SpringBootApplication
@EnableSwagger2
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3)api描述:
方法描述
模型参数描述:
参数描述:
6.2 使用WireMock快速伪造RESTful服务
1)下载WireMock的jar包
2)运行WireMock服务器端
java -jar wiremock-standalone-2.20.0.jar --port 8000
3)使用Java代码,描述规则
public class MockServer {
public static void main(String[] args) throws IOException {
WireMock.configureFor(8000);
WireMock.removeAllMappings(); //清空urlMapping mock("/order", "01.json");
}
public static void mock(String url, String file) throws IOException {
ClassPathResource classPathResource = new ClassPathResource("mock/response/"+file);
String content = FileUtils.readFileToString(classPathResource.getFile(), "UTF-8");
System.out.println(content);
WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(url))
.willReturn(WireMock.aResponse().withBody(content)
.withStatus(200)));
WireMock.saveMappings();
}
}
乱码?
withHeader("content-type", "application/json;charset=utf-8")
将mapping保存起来,下次启动WireMock时,这些mapping还存在
end
spring security入门的更多相关文章
- SpringBoot集成Spring Security入门体验
一.前言 Spring Security 和 Apache Shiro 都是安全框架,为Java应用程序提供身份认证和授权. 二者区别 Spring Security:重量级安全框架 Apache S ...
- Spring Security 入门(基本使用)
Spring Security 入门(基本使用) 这几天看了下b站关于 spring security 的学习视频,不得不说 spring security 有点复杂,脑袋有点懵懵的,在此整理下学习内 ...
- Spring Security 入门(1-1)Spring Security是什么?
1.Spring Security是什么? Spring Security 是一个安全框架,前身是 Acegi Security , 能够为 Spring企业应用系统提供声明式的安全访问控制. Spr ...
- Spring Security 入门
一.Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配 ...
- Spring Security 入门 (二)
我们在篇(一)中已经谈到了默认的登录页面以及默认的登录账号和密码. 在这一篇中我们将自己定义登录页面及账号密码. 我们先从简单的开始吧:设置自定义的账号和密码(并非从数据库读取),虽然意义不大. 上一 ...
- Spring Security 入门(一)
当你看到这篇文章时,我猜你肯定是碰到令人苦恼的问题了,我希望本文能让你有所收获. 本人几个月前还是 Spring 小白,几个月走来,看了 Spring,Spring boot,到这次的 Spring ...
- Spring Security 入门—内存用户验证
简介 作为 Spring 全家桶组件之一,Spring Security 是一个提供安全机制的组件,它主要解决两个问题: 认证:验证用户名和密码: 授权:对于不同的 URL 权限不一样,只有当认证的用 ...
- 030 SSM综合练习06--数据后台管理系统--SSM权限操作及Spring Security入门
1.权限操作涉及的三张表 (1)用户表信息描述users sql语句: CREATE TABLE users ( id ) DEFAULT SYS_GUID () PRIMARY KEY, email ...
- Spring Security 入门详解(转)
1.Spring Security介绍 Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别 处理 ...
- Spring Security入门(1-13)Spring Security的投票机制和投票器
1.三种表决方式,默认是 一票制AffirmativeBased public interface AccessDecisionManager { /** * 通过传递的参数来决定用户是否有访问对应受 ...
随机推荐
- 【05】循序渐进学 docker:系统资源和网络
写在前面的话 在上一篇学习 Dockerfile 的时候其实还有几个相当重要得关键中没有谈到,但没关系,在后面的内容会单独提出来一个一个的学习.这里就先谈谈关于资源的控制个容器的网络~ 资源限制 其实 ...
- 如何在VMware Workstation11的Windows Server 2008 R2中安装XAMPP?
我在VMware Workstation11的Windows Server 2008 R2打算安装XAMPP,但是总是有问题,经过两天的不懈努力,终于实现了,下面我具体说一说我遇到的问题和解决方法! ...
- [转]解读Unity中的CG编写Shader系列7——漫反射
如果前面几个系列文章的内容过于冗长缺乏趣味着实见谅,由于时间原因前面的混合部分还没有写完,等以后再补充,现在开始关于反射的内容了.折射与反射在物理世界中,光的反射与折射往往是同时存在的,光源由真空或者 ...
- centos7 修改网卡eth0 关闭ipv6 问题总结
1. 首先关闭"NetworkManager" 服务. 然后编辑网卡的配置文件将里面的NAME DEVICE项修改为eth0 vim /etc/sysconfig/network- ...
- 集成 jpush-react-native 常见问题汇总 (iOS 篇)
给 iOS 应用添加推送功能是一件比较麻烦的事情,本篇文章收集了集成 jpush-react-native 的常见问题,目的是为了帮助用户更好地排查问题 1. 收不到推送 确保是在真机上测试,而不是在 ...
- Ionic2实战——按模块划分app 创建多module
http://www.jianshu.com/p/d94324b722af 背景 用ionic2开发过一两个小功能的朋友都会发现,每新建一个页面都需要在\src\app\app.module.ts中添 ...
- TortoiseSVN查看修改时报错的解决方法
提交Bug后很快就修复了,给Stefan点个赞.大家等新版本(1.11.1)发布就可以了. -------------------------分割线下是原文---------------------- ...
- 7.pytest中的 plugin
一直想弄弄清这里的东西,一直各种因素delay,今天务必要搞搞清 一.先从官方文档上尝试去解读下什么是plugin和hook 网上有现成的对你适用的插件时候,我们可以直接pip安装,拿来使用即可:但是 ...
- nodemon详解
1.介绍 Nodemon是一个使用工具,它将会见监视源文件中任何的更改并自动重启服务器.Nodemon不会对你的代码产生额外的更改,它只是node命令的替代品.因为当你修改源文件后,如果你用的是原来的 ...
- 【算法笔记】B1045 快速排序
1045 快速排序 (25 分) 著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边. 给定划分后 ...