zoukankan      html  css  js  c++  java
  • 记一次学习SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice

    今天老板给我了一套代码,然后我就拿过去研究,代码的风格是SSM + Shiro + nginx + SpringBoot的MVC架构风格,springboot,是当下很火的一个框架,配合springcloud,dubbo可以完成分布式,当然,今天的重点不在这里,

    今天看了一下代码的组织结构,大致跟以往的项目架构类似,不过有一些还是有些区别:

    区别1:全局异常处理器。以往再写项目的时候,全局异常处理器都是自己定义在代码或者xml里(也就是声明在代码里),定义在

    afterCompletion
     HashMap<String, String> msg = new HashMap<String, String>();
            if (ex != null) {
                msg.put("result", "fail");
                if(ex instanceof CrudException){
                    CrudException exception = (CrudException) ex;
                    msg.put("messageCode", exception.getCode());
                    msg.put("messageText", ex.getMessage());
                }
                ObjectMapper mapper = new ObjectMapper();
                String json = mapper.writeValueAsString(msg);
                response.setContentType("application/json;charset=UTF-8");
                response.setHeader("Pragma", "No-cache");
                response.setHeader("Cache-Control", "no-cache");
                response.setDateHeader("Expires", 0);
                PrintWriter out = response.getWriter();
                out.print(json);
                out.flush();
                out.close();

    这个是传统的全局异常定义的写法,在Spring4.2之后,有了新的写法,看下面:

    比如:

    当然这个写法是SpringBoot的写法,spring的写法就是定义在xml里面,这里就不多说。下来是新项目用到的,也不算新写法,就是个人第一次见到这个,整理了一下,

    这样就,相当于对指定异常的捕捉了,@RestControllerAdvice 意思是把这个类当作bean的一个通知类,通知类可以实现SpringAOP的功能,也可以实现拦截器的功能,验证TOKEN,跨域问题比较常见

    这个是区别1;

    下来是 区别2:

      对请求的Json串解密,以及对响应的Json加密。这个就牵扯到了加解密问题了(暂不深讨,本例用的是AES加解密,本例未展示出AES工具类,如需要,请自行百度:AESUtil工具类)

      过程就是:

        以响应为先:实现ResponseBodyAdvice 接口并实现其方法,在beforeBodyWrite方法进行对响应的Json串加密修改等操作,这里你可以借鉴拦截器的后置方法,或者说

    springAOP的返回通知,在这里我使用了自定义注解校验(如果说 Controller层有该注解则加密数据——对某些重要handler进行保护),下来晾代码:

    @RestController
    public class IndexController {
    @GetMapping(value = "/index/{id}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @JsonController(encode = true)
    //加解密标识 public Object index(@PathVariable(required = false,value = "id") Integer id, @RequestBody(required = false)String name){
      List list
    = resourceService.selectAll();

    // mqSendMessage.sendMessage(MqEnums.TOPIC,MqEnums.LOGIN.getValue()+id,new BasUser());

    // AssertUtil.isNullOrEmpty(null,"sys_error");

    return "Hello World"+id +" "+ JsonUtils.toJson(list); }}

    一切操作看代码:代码中自定义的注解JsonController就是作为加密的标识,下来是配置关键环节了:ResponseBodyAdvice接口,当然,在配置这个接口之前要先声明ControllerAdvice注解。

    package org.choviwu.example.base;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.choviwu.example.common.annatation.JsonController;
    import org.choviwu.example.common.util.AESUtil;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    import java.io.IOException;
    import java.lang.reflect.Type;
    
    /**
     * 对请求的Json加解密
     */
    @RestControllerAdvice(basePackages = "org.choviwu")
    public class ResultResponse implements ResponseBodyAdvice<Object> {
    
        private String key = "1fdsv3choviwu@#~";
    
        @Override
        public boolean supports(MethodParameter methodParameter, Class aClass) {
            return true;
        }
    
        /**
         * 加密Json
         * @param o  加密的Json
         * @return
         */
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            //是否加密Json
            if(methodParameter.getMethod().isAnnotationPresent(JsonController.class)){
                JsonController jsonController = methodParameter.getMethod().getAnnotation(JsonController.class);
                //如果加密
                if(jsonController.encode()){
                    //TODO
                    ObjectMapper objectMapper = new ObjectMapper();
                    try {
                       String result =  objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
                        return AESUtil.getInstance().encrypt(result,key);//加密
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return o;
        }
    }

    这样就完成了加密响应参数的操作了;

    下来是声明请求解密:

    直接上代码:

    package org.choviwu.example.base;
    
    import org.apache.commons.io.IOUtils;
    import org.choviwu.example.common.annatation.MyConvert;
    import org.choviwu.example.common.annatation.convert.JsonConvert;
    import org.choviwu.example.common.util.AESUtil;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.Type;
    
    @RestControllerAdvice
    public class ApiRequest implements RequestBodyAdvice {
    
    
        @Override
        public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
            return true;
        }
    
        @Override
        public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
    
            return o;
        }
    
        @Override
        public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
            try {
                if(methodParameter.getMethod().isAnnotationPresent(MyConvert.class)){
                    Object obj = aClass.newInstance();
                    JsonConvert convert = new JsonConvert();
                    convert.convert(obj);
                    return new DHttpInputMessage(httpInputMessage);
                }
            }catch (Exception e){ }
            return httpInputMessage;
        }
    
        @Override
        public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
            return o;
        }
    
        public static class DHttpInputMessage implements HttpInputMessage{
            private HttpHeaders headers;
    
            private InputStream body;
            private String key = "1fdsv3choviwu@#~";
            public DHttpInputMessage(HttpInputMessage inputMessage) throws IOException {
                this.headers = inputMessage.getHeaders();
                this.body = IOUtils.toInputStream(AESUtil.getInstance().decrypt(IOUtils.toString(inputMessage.getBody()),key));
            }
    
            @Override
            public InputStream getBody() throws IOException {
                return body;
            }
    
            @Override
            public HttpHeaders getHeaders() {
                return headers;
            }
        }
    }

    注:在你请求的Controller里面的方法(Mapping)时候,必须要声明@RequestBody,否则,拦截器不会进入你的RequestBodyAdvice

    @RequestBody(required = false)String name
    参数填写 name={"abc"}
    如果看不懂,请自行学习SpringMVC SpringBoot基础

    至此,学习完成!
    记今天学习的成果。
    2018/05/03



  • 相关阅读:
    [o] SQLite数据库报错: Invalid column C
    startActivityForResult和setResult详解
    [o] duplicate column name: _id 问题解决
    [O] SQLite数据库报错:no such column
    [原创] SQLite数据库使用清单(下)
    [原创] SQLite数据库使用清单(上)
    iOS CocoaPods详解之 Analyzing dependencies
    iOS UILabe的详细使用及特殊效果
    一个简单的socket通信小demo
    iOS Lable给文字添加中划线和下划线
  • 原文地址:https://www.cnblogs.com/ChoviWu/p/8987895.html
Copyright © 2011-2022 走看看