.需求
在项目中spring web服务为外部APP提供rest接口,为了 安全考虑 一般会加入自己的验证,常规 的签名+数据加密, 当然一个好的架构师或者负责人会在项目初期会考虑到的问题现老代码一般是在@Controller层每个request的开始和结尾处做的加密解密操作,这样的代码重复度很高,而且不利于更好的利用Spring框架的HttpMessageConverter达到java丰富类型的自动转换。因为APP\传到后台是加密后的数据。无法做到自动拆箱,所以说我们要在接受参数之前进行解密操作,在返回数据的时候进行加密操作!
2.实现方式
- 拦截器实现
- 切面拦截实现
- 自定义注解实现
- 1考虑前两种的性能,以及复用性本文采用 自定义注解去实现,当然这只是其中一部分原因。
- 2是看起来比较厉害对吧。(程序员都是骚的不行滴。O(∩_∩)O)
3.具体代码
- 包命名
- 我认为一份好的代码以及要有规矩,当然我是工作不太久,但是我在尽量对我的代码和各种命令写好。
- com.xxx.open
- com.xxx.open.common.annotation -------------------- 自定义注解包
- com.xxx.common.container -------------------- 容器产量
- com.xxx.common.entity -------------------- 实体类
- com.xxx.common.exception -------------------- 自定义异常
- com.xxx.common.support -------------------- 对自定义注解算是的实现吧
- com.xxx.util -------------------- 加密解密工具类
- 自定义的解析器会被springMvc只带的解析器优先解析,而且无法排序,具体原因代码是:
- private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
- ArrayList resolvers = new ArrayList();
- resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false));
- resolvers.add(new RequestParamMapMethodArgumentResolver());
- resolvers.add(new PathVariableMethodArgumentResolver());
- resolvers.add(new PathVariableMapMethodArgumentResolver());
- resolvers.add(new MatrixVariableMethodArgumentResolver());
- resolvers.add(new MatrixVariableMapMethodArgumentResolver());
- resolvers.add(new ServletModelAttributeMethodProcessor(false));
- resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice));
- resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters(), this.requestResponseBodyAdvice));
- resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory()));
- resolvers.add(new RequestHeaderMapMethodArgumentResolver());
- resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory()));
- resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory()));
- resolvers.add(new SessionAttributeMethodArgumentResolver());
- resolvers.add(new RequestAttributeMethodArgumentResolver());
- resolvers.add(new ServletRequestMethodArgumentResolver());
- resolvers.add(new ServletResponseMethodArgumentResolver());
- resolvers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice));
- resolvers.add(new RedirectAttributesMethodArgumentResolver());
- resolvers.add(new ModelMethodProcessor());
- resolvers.add(new MapMethodProcessor());
- resolvers.add(new ErrorsMethodArgumentResolver());
- resolvers.add(new SessionStatusMethodArgumentResolver());
- resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
- if(this.getCustomArgumentResolvers() != null) {
- resolvers.addAll(this.getCustomArgumentResolvers());
- }
-
- resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true));
- resolvers.add(new ServletModelAttributeMethodProcessor(true));
- return resolvers;
- }
如果接受参数是Map获取是Map的子类的话,会优先被ServletRequestMethodArgumentResolver优先执行的,所有我们这增加一个自己的实现类,当然牺牲了通用性。
-
- /*
- * Copyright 2002-2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package com.caigaoqing.tech.common.entity;
-
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Set;
-
- /**
- * 在spring mcv中 如果接受参数是Map或是map的子类的话会首先被springmvc自己的拦截器拦截进行处理
- * 这里实现自己的map
- * @param <K>
- * @param <V>
- */
- public class MapWrapper<K, V> {
-
- private Map<K, V> innerMap = new HashMap<K, V>();
-
- public void setInnerMap(Map<K, V> innerMap) {
- this.innerMap = innerMap;
- }
-
- public Map<K, V> getInnerMap() {
- return innerMap;
- }
-
- public void clear() {
- innerMap.clear();
- }
-
- public boolean containsKey(Object key) {
- return innerMap.containsKey(key);
- }
-
- public boolean containsValue(Object value) {
- return innerMap.containsValue(value);
- }
-
- public Set<Map.Entry<K, V>> entrySet() {
- return innerMap.entrySet();
- }
-
- public boolean equals(Object o) {
- return innerMap.equals(o);
- }
-
- public V get(Object key) {
- return innerMap.get(key);
- }
-
- public int hashCode() {
- return innerMap.hashCode();
- }
-
- public boolean isEmpty() {
- return innerMap.isEmpty();
- }
-
- public Set<K> keySet() {
- return innerMap.keySet();
- }
-
- public V put(K key, V value) {
- return innerMap.put(key, value);
- }
-
- public void putAll(Map<? extends K, ? extends V> m) {
- innerMap.putAll(m);
- }
-
- public V remove(Object key) {
- return innerMap.remove(key);
- }
-
- public int size() {
- return innerMap.size();
- }
-
- public Collection<V> values() {
- return innerMap.values();
- }
-
- public Map<K, V> toMap() {
- return innerMap;
- }
-
- @Override
- public String toString() {
- return innerMap.toString();
- }
- }
在转换参数的时候判断
- //mapWrapper类型
- if (MapWrapper.class.isAssignableFrom(clazz)){
- MapWrapper mapWrapper=new MapWrapper();
- Map target =(Map) JSON.parseObject(bodyObj.toString());
- mapWrapper.setInnerMap(target);
- result=(Object)mapWrapper;
- }
接受参数的接口是:
- @ResponseBodyEncrypt()
- @PostMapping("test")
- public Map getMap(@RequestBodyDecrypt MapWapper userName){
- return userName.toMap();
- }
4.注意事项
我代码写的不好,还请大家多多见谅!!!!
5.结果
著作权归作者所有,转载请标志作者。2018/08/17
上面应该是接受参数 解密的
代码应该没有问题的,具体查看码云:
https://gitee.com/CaiGaoQing/open-api