1. 程式人生 > >記一次學習SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice

記一次學習SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice

with except 學習 就是 ports mes selectall extend roc

今天老板給我了一套代碼,然後我就拿過去研究,代碼的風格是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



記一次學習SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice