美文网首页SpringBoot极简教程 · Spring Boot
Spring Security项目Spring MVC开发RES

Spring Security项目Spring MVC开发RES

作者: 郭少华 | 来源:发表于2018-08-30 15:42 被阅读5次

    查询请求

    常用注解

    • @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);
        }
    

    自定义注解

    image.png

    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;
        }
    

    查看返回的异常信息


    image.png

    处理状态码错误

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


    image.png

    RESTful API的拦截

    过滤器(Filter)

    image.png

    创建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标签去除


    image.png
    @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)

    image.png

    创建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文件


    image.png
    @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)

    image.png
    @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的配置类


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

    相关文章

      网友评论

        本文标题:Spring Security项目Spring MVC开发RES

        本文链接:https://www.haomeiwen.com/subject/izrgpftx.html