前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次学习SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice【技能篇】

记一次学习SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice【技能篇】

作者头像
简单的程序员
发布2020-04-20 12:06:26
1.7K0
发布2020-04-20 12:06:26
举报
文章被收录于专栏:奕仁专栏奕仁专栏

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

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

区别1

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

代码语言:javascript
复制
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进行保护),下来晾代码:

代码语言:javascript
复制
	@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注解。

代码语言:javascript
复制
	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;
		}
	}

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

下来是声明请求解密:

直接上代码:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-12-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 区别1:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档