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 { /** * 通过传递的参数来决定用户是否有访问对应受 ...
随机推荐
- BZOJ4710 分特产
题目链接:戳我 容斥题. 设\(f[i]\)表示至多有i个人能够分到(也就是至少n-i个人分不到)的方案数 \(f[i]=\prod_{j=1}^mC_{a[j]+i-1}^i-1\) a[j]表示的 ...
- offsetWidth和width的区别
1.offsetWidth属性可以返回对象的padding+border+width属性值之和,style.width返回值就是定义的width属性值. 2.offsetWidth属性仅是可读属性,而 ...
- 打造一款1kb大马并且处理D盾以及安全狗拦截与查杀
在之前sky666提到了关于大马被waf拦的问题,我决定手动去过一下bypass.可是发现怎么也过不去查杀,更别说拦截了.对此无奈,只好花了个通宵去处理一下.顺便一提,理论过所有Waf,并且被杀只需要 ...
- 对cookie,session,token,jwt的理解
对这几个东西有点凌乱了,今天有时间整理下 cookie Cookie的诞生 由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的.Cookie诞生的最初目的是为了存储web中的状态信息,以方便 ...
- 在eclips中配置maven
可参考https://jingyan.baidu.com/article/59703552cb9b988fc00740a4.html
- 包子凑数(dp思想)
问题描述: 小明几乎每天早晨都会在一家包子铺吃早餐.他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子.每种蒸笼都有非常多笼,可以认为是无限笼.每当有顾客想买X个包子,卖包子的大叔就会迅速选 ...
- 安装Windows 64 位 mysql 最新版本解压包中没有data目录和my-default.ini及服务无法启动的快速解决办法
mysql官网下载地址:https://dev.mysql.com/downloads/mysql/ 首先安装包解压后,没有网上教程里面提到的data文件夹和my-default.ini 配置环境变量 ...
- 2.使用ngx_http_auth_basic_module模块为不带认证的资源添加授权
1.首先需要生成用户名和密码 使用openssl来生成,生成命令(openssl在安装nginx的时候已经安装) echo "kibana:$(openssl passwd -crypt y ...
- 一个迷你的 Node.js 基于 Express 的 MVR 模式的 API工程 的分析
1. 工程说明 该工程是基于 Express 库,编写的一个 API 查询返回的一个微型应用. API Resource 就是把 API 的内容当做网络资源去处理.工程中的路由访问也是返回 API 内 ...
- python爬虫专栏学习
知乎的一个讲python的专栏,其中爬虫的几篇文章,偏入门解释,快速看了一遍. 入门 爬虫基本原理:用最简单的代码抓取最基础的网页,展现爬虫的最基本思想,让读者知道爬虫其实是一件非常简单的事情. 爬虫 ...