最近公司有个代码规范变动。
原本接口是这样的
后台接口是这样接受的
修改后为
原本开发的好好的,结果因为接口规范变动,导致所有接口动用不了,本来想在实体类上做继承公共的分页类,结果发现实体类上已经继承了其他类,而且对代码改动量较大遂放弃。
于是乎想到能不能利用spring web中的拦截器做文章,在参数还未开始解析成实体类前就将参数提前转换好。
1.声明参数注解类
/**
* @author weijunzhe
* @Description: <BASE64注解>
* @Date: 2022/10/23/22:16
**/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditions {
/**
* 是否转为BASE64
* */
boolean value() default true;
Class<?> type() default Object.class;
}
2. 编写参数解析器
/**
* 参数解析器
* @author weijunzhe
*/
public class ConditionHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
private static final String POINT = ".";
private static final String LEFT_PARENTHESIS = "[";
private static final String RIGHT_PARENTHESIS = "]";
private static final String PARENTHESIS = "[]";
private static final String CONTENT_TYPE = "application/json";
private final Logger logger = LoggerFactory.getLogger(ConditionHandlerMethodArgumentResolver.class);
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(Conditions.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory){
//获取JSON字符串
String jsonStr;
//判断content-type是否是application/json 的数据类型
String contentType = nativeWebRequest.getHeader("content-type");
Conditions methodAnnotation = methodParameter.getParameterAnnotation(Conditions.class);
if (StringUtils.isNotBlank(contentType) && contentType.contains(CONTENT_TYPE)){
jsonStr = getJSONParam(nativeWebRequest);
}else {
jsonStr = parseParamToJSONStr(nativeWebRequest);
}
try {
PageQuery pageQuery = JSONUtil.toBean(jsonStr, PageQuery.class);
pageQuery.setConditions(JSONUtil.toBean(jsonStr, methodAnnotation.type()));
return pageQuery;
}catch (JSONException e){
logger.error("resolveArgument中JSON.parseObject方法出错:"+e.getMessage(),e);
return null;
}
}
/**
*@Description 获取JSON字符串中的数据
*@author weijunzhe
*/
private String getJSONParam(NativeWebRequest request){
StringBuilder stringBuilder = new StringBuilder();
try {
//1.获取输入流
BufferedReader stramReader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(request.getNativeRequest(HttpServletRequest.class)).getInputStream()));
//2.写入数据到StringBuilder
String line;
while ((line = stramReader.readLine()) != null){
stringBuilder.append(line);
}
}catch (Exception e){
logger.error("获取JSON字符串中的数据错误:"+e.getMessage(),e);
}
return stringBuilder.toString();
}
/**
*@Description 将user.id=1这种形式的数据转为{user:{id:1}}形式
*@author weijunzhe
*/
private String parseParamToJSONStr(NativeWebRequest request){
Map<String,String [] > conditionMap = request.getParameterMap();
JSONObject jsonObject = new JSONObject();
Iterator<String> names = request.getParameterNames();
while (names.hasNext()){
String name = names.next();
String [] value = conditionMap.get(name);
if (value != null){
parseHavePointParamToJSON(jsonObject,name,value);
}
}
return jsonObject.toString();
}
/**
*@Description 处理带有点的参数
*@author weijunzhe
*/
private void parseHavePointParamToJSON(JSONObject jsonObject,String name,String [] value){
//处理中括号
if (name.contains(LEFT_PARENTHESIS)){
name = name
.replace(PARENTHESIS,"")
.replace(LEFT_PARENTHESIS,POINT)
.replace(RIGHT_PARENTHESIS,"");
}
if (!name.contains(POINT)){
//如果没有小数点,证明已经是最后一个了
//判断是否是已经设置过值
if (value.length>1){
//如果是组数,则以数组的形式存放数据
JSONArray jsonArray = new JSONArray();
jsonArray.addAll(Arrays.asList(value));
jsonObject.put(name,jsonArray);
}else {
jsonObject.put(name,value[0]);
}
}else {
//如果还有小数点
int pointIndex = name.indexOf(POINT);
String tempName = name.substring(0,pointIndex);
String subName = name.substring(name.indexOf(POINT)+1,name.length());
JSONObject subJSONObject;
//判断是否已经有对应的属性了
if (jsonObject.getJSONObject(tempName) == null){
//如果没有
subJSONObject = new JSONObject();
}else {
//如果有
subJSONObject = jsonObject.getJSONObject(tempName);
}
jsonObject.put(tempName,subJSONObject);
//递归处理
parseHavePointParamToJSON(subJSONObject,subName,value);
}
}
}
3. 将自定义参数解析器添加到spring web中
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new ConditionHandlerMethodArgumentResolver());
}
}
4. 最后在方法的参数上添加该注解
/**
* 修改用户
*/
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PostMapping
public AjaxResult updateProfile(@Conditions(type = SysUser.class) PageQuery<SysUser> pageQuery)
{
System.err.println(pageQuery.getConditions());
return AjaxResult.success(pageQuery);
}
测试后发现一切正常,不用再去动实体类代码= =。
大功告成,下班!!!