Spring Security项目Spring MVC开发RESTful API(二)

栏目: 后端 · 发布时间: 6年前

内容简介:编写一个简单的UserController类@PageableDefault SpingData分页参数 page当前页数默认0开始 sizi每页个数默认10 sort 排序在demo的pom.xml里面引入spirngboot的测试

查询请求

常用注解

  • @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) //运行器
@SpringBootTest
public 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
@AllArgsConstructor
public 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) //运行器
@SpringBootTest
public 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
@AllArgsConstructor
public 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) //运行器
@SpringBootTest
public 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
@AllArgsConstructor
public 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) //运行器
@SpringBootTest
public 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);
    }

自定义注解

Spring Security项目Spring MVC开发RESTful API(二)

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) //运行器
@SpringBootTest
public 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;
    }

查看返回的异常信息

Spring Security项目Spring MVC开发RESTful API(二)

处理状态码错误

创建文件结构如下404错误将跳转对应页面

Spring Security项目Spring MVC开发RESTful API(二)

RESTful API的拦截

过滤器(Filter)

Spring Security项目Spring MVC开发RESTful API(二)

创建filter文件

@Component
public 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标签去除

Spring Security项目Spring MVC开发RESTful API(二)

@Configuration
public 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)

Spring Security项目Spring MVC开发RESTful API(二)

创建Interceptor文件

@Component
public 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文件

Spring Security项目Spring MVC开发RESTful API(二)

@Configuration
public 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)

Spring Security项目Spring MVC开发RESTful API(二)

@Aspect
@Component
public 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
@AllArgsConstructor
public 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的配置类

Spring Security项目Spring MVC开发RESTful API(二)

@Configuration
@EnableSwagger2
public 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 用在实体对象的字段上 用于描述字段含义

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Haskell School of Expression

The Haskell School of Expression

Paul Hudak / Cambridge University Press / 2000-01 / USD 95.00

Functional programming is a style of programming that emphasizes the use of functions (in contrast to object-oriented programming, which emphasizes the use of objects). It has become popular in recen......一起来看看 《The Haskell School of Expression》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具