查询请求常用注解@RestController 标明此Controller提供RestAPI@RequestMapping 映射http请求url到java方法@RequestParam 映射请求参数到java方法到参数@PageableDefault 指定分页参数默认值编写一个简单的UserController类@RestController@RequestMapping(value = “/user”)public class UserController { @RequestMapping(method = RequestMethod.GET) public List<User> query(@RequestParam(name = “username”,required = true) String username, @PageableDefault(page = 1,size = 20,sort = “username”,direction = Sort.Direction.DESC)Pageable pageable){ System.out.println(pageable.getSort()); List<User>users=new ArrayList<>(); users.add(new User(“aaa”,“111”)); users.add(new User(“bbb”,“222”)); users.add(new User(“ddd”,“333”)); return users; }}@PageableDefault SpingData分页参数 page当前页数默认0开始 sizi每页个数默认10 sort 排序Srping boot 测试用例在demo的pom.xml里面引入spirngboot的测试 <!–spring测试框架–> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>测试/user接口@RunWith(SpringRunner.class) //运行器@SpringBootTestpublic class UserControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void stup(){ mockMvc= MockMvcBuilders.webAppContextSetup(wac).build(); } //测试用例 @Test public void whenQuerSuccess() throws Exception { String result=mockMvc.perform(MockMvcRequestBuilders.get("/user") //传过去的参数 .param(“username”,“admin”) .contentType(MediaType.APPLICATION_JSON_UTF8)) //判断请求的状态吗是否成功,200 .andExpect(MockMvcResultMatchers.status().isOk()) //判断返回的集合的长度是否是3 .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3)) //打印信息 .andDo(MockMvcResultHandlers.print()) .andReturn().getResponse().getContentAsString(); //打印返回结果 System.out.println(result); }jsonPath文档语法查询地址用户详情请求常用注解@PathVariable 映射url片段到java方法参数@JsonView 控制json输出内容实体对象@NoArgsConstructor@AllArgsConstructorpublic class User { public interface UserSimpleView{}; public interface UserDetailView extends UserSimpleView{}; private String username; private String password; @JsonView(UserSimpleView.class) public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @JsonView(UserDetailView.class) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}Controller类@RestController@RequestMapping(value = “/user”)public class UserController { @RequestMapping(value = “/{id:\d+}",method = RequestMethod.GET) // 正则表达式 :\d+ 表示只能输入数字 //用户名密码都显示 @JsonView(User.UserDetailView.class) public User userInfo(@PathVariable String id){ User user=new User(); user.setUsername(“tom”); return user; }}测试用例@RunWith(SpringRunner.class) //运行器@SpringBootTestpublic class UserControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void stup(){ mockMvc= MockMvcBuilders.webAppContextSetup(wac).build(); } //用户详情用例 @Test public void whenUserInfoSuccess() throws Exception { String result=mockMvc.perform(MockMvcRequestBuilders.get("/user/1”) .contentType(MediaType.APPLICATION_JSON_UTF8)) //判断请求的状态吗是否成功,200 .andExpect(MockMvcResultMatchers.status().isOk()) //判断返回到username是不是tom .andExpect(MockMvcResultMatchers.jsonPath("$.username").value(“tom”)) //打印信息 .andDo(MockMvcResultHandlers.print()) .andReturn().getResponse().getContentAsString(); //打印返回结果 System.out.println(result); }}用户处理创建请求常用注解@RequestBody 映射请求体到java方法到参数@Valid注解和BindingResult验证请求参数合法性并处理校验结果实体对象@NoArgsConstructor@AllArgsConstructorpublic class User { public interface UserSimpleView{}; public interface UserDetailView extends UserSimpleView{}; private String id; private String username; //不允许password为null @NotBlank private String password; private Date birthday; @JsonView(UserSimpleView.class) public String getId() { return id; } public void setId(String id) { this.id = id; } @JsonView(UserSimpleView.class) public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @JsonView(UserDetailView.class) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @JsonView(UserSimpleView.class) public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; }}Controller类 @RequestMapping(method = RequestMethod.POST) @JsonView(User.UserSimpleView.class) //@Valid启用校验password不允许为空 public User createUser(@Valid @RequestBody User user, BindingResult errors){ //如果校验有错误是true并打印错误信息 if(errors.hasErrors()){ errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage())); } System.out.println(user.getUsername()); System.out.println(user.getPassword()); System.out.println(user.getBirthday()); user.setId(“1”); return user; }测试用例@RunWith(SpringRunner.class) //运行器@SpringBootTestpublic class UserControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void stup(){ mockMvc= MockMvcBuilders.webAppContextSetup(wac).build(); } //用户创建用例 @Test public void whenCreateSuccess() throws Exception { Date date=new Date(); String content="{"username":"tom","password":null,"birthday":"+date.getTime()+"}"; String result=mockMvc.perform(MockMvcRequestBuilders.post("/user") .content(content) .contentType(MediaType.APPLICATION_JSON_UTF8)) //判断请求的状态吗是否成功,200 .andExpect(MockMvcResultMatchers.status().isOk()) //判断返回到username是不是tom .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(“1”)) .andReturn().getResponse().getContentAsString(); //打印返回结果 System.out.println(result); }}修改和删除请求验证注解| 注解 | 解释 | | ——– | ——– | | @NotNull | 值不能为空 | | @Null | 值必须为空 | | @Pattern(regex=) | 字符串必须匹配正则表达式 | | @Size(min=,max=) | 集合的元素数量必须在min和max之间 | | @Email | 字符串必须是Email地址 | | @Length(min=,max=) | 检查字符串长度 | | @NotBlank | 字符串必须有字符 | | @NotEmpty | 字符串不为null,集合有元素 | | @Range(min=,max=) | 数字必须大于等于min,小于等于max | | @SafeHtml | 字符串是安全的html | | @URL | 字符串是合法的URL | | @AssertFalse | 值必须是false | | @AssertTrue | 值必须是true | | @DecimalMax(value=,inclusive) | 值必须小于等于(inclusive=true)/小于(inclusive=false) value指定的值 | | @DecimalMin(value=,inclusive) | 值必须大于等于(inclusive=true)/大于(inclusive=false) value指定的值 | | @Digits(integer=,fraction=) | integer指定整数部分最大长度,fraction小数部分最大长度 | | @Future | 被注释的元素必须是一个将来的日期 | | @Past | 被注释的元素必须是一个过去的日期 | | @Max(value=) | 值必须小于等于value值 | | @Min(value=) | 值必须大于等于value值 |自定义注解修改请求实体对象@NoArgsConstructor@AllArgsConstructorpublic class User { public interface UserSimpleView{}; public interface UserDetailView extends UserSimpleView{}; private String id; //自定义注解 @MyConstraint(message = “账号必须是tom”) private String username; //不允许password为null @NotBlank(message = “密码不能为空”) private String password; //加验证生日必须是过去的时间 @Past(message = “生日必须是过去的时间”) private Date birthday; @JsonView(UserSimpleView.class) public String getId() { return id; } public void setId(String id) { this.id = id; } @JsonView(UserSimpleView.class) public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @JsonView(UserDetailView.class) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @JsonView(UserSimpleView.class) public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; }}Controller类 @RequestMapping(value = “/{id:\d+}",method = RequestMethod.PUT) @JsonView(User.UserSimpleView.class) //@Valid启用校验password不允许为空 public User updateUser(@Valid @RequestBody User user, BindingResult errors){ //如果校验有错误是true并打印错误信息 if(errors.hasErrors()){ errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage())); } System.out.println(user.getUsername()); System.out.println(user.getPassword()); System.out.println(user.getBirthday()); user.setId(“1”); return user; }测试用例@RunWith(SpringRunner.class) //运行器@SpringBootTestpublic class UserControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void stup(){ mockMvc= MockMvcBuilders.webAppContextSetup(wac).build(); } //用户修改用例 @Test public void whenUpdateSuccess() throws Exception { //当前时间加一年 Date date = new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); String content = “{"id":"1","username":"44","password":null,"birthday":” + date.getTime() + “}”; String result = mockMvc.perform(MockMvcRequestBuilders.put("/user/1”) .content(content) .contentType(MediaType.APPLICATION_JSON_UTF8)) //判断请求的状态吗是否成功,200 .andExpect(MockMvcResultMatchers.status().isOk()) //判断返回到username是不是tom .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(“1”)) .andReturn().getResponse().getContentAsString(); //打印返回结果 System.out.println(result); }自定义注解MyConstraint类import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;//作用在字段跟方法上面@Target({ElementType.FIELD,ElementType.METHOD})//运行时注解@Retention(RetentionPolicy.RUNTIME)//需要校验注解的类@Constraint(validatedBy = MyConstraintValidator.class)public @interface MyConstraint { String message() default “{org.hibernate.validator.constraints.NotBlank.message}”; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {};}MyConstraintValidator类import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;//范型1.验证的注解 2.验证的数据类型public class MyConstraintValidator implements ConstraintValidator<MyConstraint,Object> { @Override public void initialize(MyConstraint myConstraint) { //校验器初始化的规则 } @Override public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { //校验username如果是tom验证通过 if (value.equals(“tom”)){ return true; }else{ return false; } }}删除请求Controller类 @RequestMapping(value = “/{id:\d+}",method = RequestMethod.DELETE) //@Valid启用校验password不允许为空 public void deleteUser(@PathVariable String id){ System.out.println(id); }测试用例@RunWith(SpringRunner.class) //运行器@SpringBootTestpublic class UserControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void stup(){ mockMvc= MockMvcBuilders.webAppContextSetup(wac).build(); } //用户删除用例 @Test public void whenDeleteSuccess() throws Exception { mockMvc.perform(MockMvcRequestBuilders.delete("/user/1”) .contentType(MediaType.APPLICATION_JSON_UTF8)) //判断请求的状态吗是否成功,200 .andExpect(MockMvcResultMatchers.status().isOk()); }服务异常处理把BindingResult errors去掉 @RequestMapping(method = RequestMethod.POST) @JsonView(User.UserSimpleView.class) //@Valid启用校验password不允许为空 public User createUser(@Valid @RequestBody User user){ //如果校验有错误是true并打印错误信息// if(errors.hasErrors()){// errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage()));// } System.out.println(user.getUsername()); System.out.println(user.getPassword()); System.out.println(user.getBirthday()); user.setId(“1”); return user; }查看返回的异常信息处理状态码错误创建文件结构如下404错误将跳转对应页面RESTful API的拦截过滤器(Filter)创建filter文件@Componentpublic class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(“TimeFilter init”); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println(“TimeFilter doFilter”); long start=new Date().getTime(); filterChain.doFilter(servletRequest,servletResponse); System.out.println(“耗时”+(new Date().getTime()-start)); } @Override public void destroy() { System.out.println(“TimeFilter destroy”); }}自定义filter需要吧filter文件@Component标签去除@Configurationpublic class WebConfig { @Bean public FilterRegistrationBean timeFilterRegistration(){ FilterRegistrationBean registration=new FilterRegistrationBean(); TimeFilter timeFilter=new TimeFilter(); registration.setFilter(timeFilter); //filter作用的地址 List<String>urls=new ArrayList<>(); urls.add("/user"); registration.setUrlPatterns(urls); return registration; }}拦截器(Interceptor)创建Interceptor文件@Componentpublic class TimeInterceptor implements HandlerInterceptor { //控制器方法调用之前 @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println(“preHandle”); System.out.println(“进入方法”+((HandlerMethod)o).getMethod().getName()); httpServletRequest.setAttribute(“startTime”,new Date().getTime()); //是否调用后面的方法调用是true return true; } //控制器方法被调用 @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println(“postHandle”); Long start= (Long) httpServletRequest.getAttribute(“startTime”); System.out.println(“time interceptor耗时”+(new Date().getTime()-start)); } //控制器方法完成之后 @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println(“afterCompletion”); System.out.println(“exception is”+e); }}把过滤器添加到webconfig文件@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Autowired private TimeInterceptor timeInterceptor; //过滤器 @Bean public FilterRegistrationBean timeFilterRegistration(){ FilterRegistrationBean registration=new FilterRegistrationBean(); TimeFilter timeFilter=new TimeFilter(); registration.setFilter(timeFilter); //filter作用的地址 List<String>urls=new ArrayList<>(); urls.add("/user/"); registration.setUrlPatterns(urls); return registration; } //拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor); }}切片(Aspect)@Aspect@Componentpublic class TimeAspect { //@Befor方法调用之前 //@After()方法调用 //@AfterThrowing方法调用之后 //包围,覆盖前面三种 @Around(“execution( com.guosh.web.controller.UserController.(..))”)//表达式表示usercontroller里所有方法其他表达式可以查询切片表达式 public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println(“time aspect start”); //可以获取到传入参数 Object[]args=pjp.getArgs(); for (Object arg: args) { System.out.println(“arg is”+arg); } long start=new Date().getTime(); //相当于filter里doFilter方法 Object object=pjp.proceed(); System.out.println(“time aspect耗时”+(new Date().getTime()-start)); System.out.println(“time aspect end”); return object; }}总结过滤器Filter :可以拿到原始的http请求与响应信息拦截器Interceptor :可以拿到原始的http请求与响应信息还可以拿到处理请求方法的信息切片Aspect :可以拿到方法调用传过来的值使用rest方式处理文件服务返回的上传文件后路径对象在application.yml里添加上传地址#上传文件路径uploadfiledir: filePath: /Users/shaohua/webapp/guoshsecurity@Data@NoArgsConstructor@AllArgsConstructorpublic class FileInfo { private String path;}@RestController@RequestMapping("/file")public class FileController { @Value("${uploadfiledir.filePath}") private String fileDataStorePath;//文件上传地址 @RequestMapping(method = RequestMethod.POST) public FileInfo upload(@RequestParam(“file”) MultipartFile file) throws IOException { //文件名 System.out.println(file.getOriginalFilename()); //文件大小 System.out.println(file.getSize()); //获取文件后缀名 String ext=StringUtils.getFilenameExtension(file.getOriginalFilename()); File fileDir = new File(fileDataStorePath); //判断是否创建目录 if (!fileDir.exists()) { if (!fileDir.mkdirs() || !fileDir.exists()) { // 创建目录失败 throw new RuntimeException(“无法创建目录!”); } } File localFile=new File(fileDataStorePath, UUID.randomUUID().toString().replace("-", “”)+"."+ext); file.transferTo(localFile); //返回上传的路径地址 return new FileInfo(localFile.getAbsolutePath()); } //下载文件 @RequestMapping(value ="/{id}" ,method = RequestMethod.GET) public void download(@PathVariable String id, HttpServletResponse response){ //模拟下载直接填好了下载文件名称 try(InputStream inputStream = new FileInputStream(new File(fileDataStorePath,“13a2c075b7f44025bbb3c590f7f372eb.txt”)); OutputStream outputStream=response.getOutputStream();){ response.setContentType(“application/x-download”); response.addHeader(“Content-Disposition”,“attachment;filename="+“13a2c075b7f44025bbb3c590f7f372eb.txt"”); IOUtils.copy(inputStream,outputStream); } catch (Exception e) { e.printStackTrace(); } }}使用Swagger工具在demo模块引入 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>添加swagger的配置类@Configuration@EnableSwagger2public class Swagger2Config { @Value("${sys.swagger.enable-swgger}”) private Boolean enableSwgger; @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .enable(enableSwgger) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage(“com.guosh.web”)) //swgger插件作用范围 //.paths(PathSelectors.regex("/api/.")) .paths(PathSelectors.any()) //过滤接口 .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(“SpringSecurityDemo”) //标题 .description(“API描述”) //描述 .contact(new Contact(“guoshaohua”, “http://www.guoshaohua.cn”, “”))//作者 .version(“1.0”) .build(); }}常用注解通过@Api用于controller类上对类的功能进行描述通过@ApiOperation注解用在controller方法上对类的方法进行描述通过@ApiImplicitParams、@ApiImplicitParam注解来给参数增加说明通过@ApiIgnore来忽略那些不想让生成RESTful API文档的接口通过@ApiModel 用在返回对象类上描述返回对象的意义通过@ApiModelProperty 用在实体对象的字段上 用于描述字段含义