Commit 98b55b93 authored by trumansdo's avatar trumansdo
Browse files

测试98 after emitting copyplugin 问题

parent aa115e88
......@@ -6,7 +6,6 @@ import com.ibeetl.admin.core.service.CoreBaseService;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.enums.DelFlagEnum;
import java.util.List;
import org.beetl.sql.core.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......
......@@ -25,6 +25,35 @@ public class DictCascaderElController {
@Autowired CoreDictService coreDictService;
@GetMapping("/immediateLoad")
public JsonResult<List<ElCascaderData>> immediateLoadCascaderDict(Long parentId, String type) {
if (StrUtil.isBlank(type) && parentId == null) {
return JsonResult.failMessage("parentId and type should have at least one.");
}
List<CoreDict> childDictList = coreDictService.findChildrenNodes(parentId, type);
return JsonResult.success(coreDictToElCascaderData(childDictList));
}
/**
* .将字典树转成element级联器组件的格式
*
* @author 一日看尽长安花
* @return List<ElCascaderData>
*/
private List<ElCascaderData> coreDictToElCascaderData(List<CoreDict> coreDicts) {
List<ElCascaderData> elCascaderDatas = new ArrayList<ElCascaderData>(coreDicts.size());
for (CoreDict dict : coreDicts) {
ElCascaderData data = new ElCascaderData();
data.setId(dict.getId());
data.setLabel(dict.getName());
data.setValue(dict.getValue());
List<ElCascaderData> children = coreDictToElCascaderData(dict.getChildren());
data.setChildren(children);
elCascaderDatas.add(data);
}
return elCascaderDatas.isEmpty() ? null : elCascaderDatas;
}
/**
* Method obtainDcitsByCascader ... 获取子级字典列表。如果不传父级id,只获取type指定的列表而已。
*
......@@ -32,8 +61,8 @@ public class DictCascaderElController {
* @param type of type String 子级字典列表type
* @return JsonResult<List < ElCascaderData>>
*/
@GetMapping("/tree")
public JsonResult<List<ElCascaderData>> obtainDcitsByCascader(Long parentId, String type) {
@GetMapping("/layzyLoad")
public JsonResult<List<ElCascaderData>> layzyLoadCascaderDict(Long parentId, String type) {
if (StrUtil.isBlank(type) && parentId == null) {
return JsonResult.failMessage("parentId and type should have at least one.");
}
......
......@@ -3,6 +3,7 @@ package com.ibeetl.admin.console.web;
import com.ibeetl.admin.core.entity.CoreOrg;
import com.ibeetl.admin.core.entity.ElCascaderData;
import com.ibeetl.admin.console.service.CoreOrgConsoleElService;
import com.ibeetl.admin.core.service.CoreOrgService;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.web.JsonResult;
import java.util.ArrayList;
......@@ -25,8 +26,35 @@ public class OrgCascaderElController {
@Autowired CorePlatformService corePlatformService;
@Autowired
CoreOrgConsoleElService coreOrgService;
@Autowired CoreOrgConsoleElService coreOrgConsoleElService;
@Autowired CoreOrgService coreOrgService;
@GetMapping("/immediateLoad")
public JsonResult<List<ElCascaderData>> immediateLoadCascaderDict(Long parentId) {
List<CoreOrg> childDictList = coreOrgService.findChildrenNodes(parentId);
return JsonResult.success(coreOrgToElCascaderData(childDictList));
}
/**
* .将字典树转成element级联器组件的格式
*
* @author 一日看尽长安花
* @return List<ElCascaderData>
*/
private List<ElCascaderData> coreOrgToElCascaderData(List<CoreOrg> coreDicts) {
List<ElCascaderData> elCascaderDatas = new ArrayList<ElCascaderData>(coreDicts.size());
for (CoreOrg org : coreDicts) {
ElCascaderData data = new ElCascaderData();
data.setId(org.getId());
data.setLabel(org.getName());
data.setValue(org.getId());
List<ElCascaderData> children = coreOrgToElCascaderData(org.getChidren());
data.setChildren(children);
elCascaderDatas.add(data);
}
return elCascaderDatas.isEmpty() ? null : elCascaderDatas;
}
/**
* Method obtainDcitsByCascader ...<br>
......@@ -36,9 +64,9 @@ public class OrgCascaderElController {
* @param parentId of type Long 父级id
* @return JsonResult<List < ElCascaderData>>
*/
@GetMapping("/tree")
@GetMapping("/layzyLoad")
public JsonResult<List<ElCascaderData>> obtainOrgsByCascader(Long parentId) {
List<CoreOrg> coreOrgList = coreOrgService.getOrgListByParent(parentId);
List<CoreOrg> coreOrgList = coreOrgConsoleElService.getOrgListByParent(parentId);
return JsonResult.success(convertToCascaderData(coreOrgList));
}
......
......@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
......@@ -48,7 +49,7 @@ public class UserConsoleElController {
@Function("user.add")
@PostMapping
public JsonResult<Long> addUser(@Validated(ValidateConfig.ADD.class) CoreUser user) {
public JsonResult<Long> addUser(@Validated(ValidateConfig.ADD.class) @RequestBody CoreUser user) {
if (!platformService.isAllowUserName(user.getCode())) {
return JsonResult.failMessage("不允许的注册名字 " + user.getCode());
}
......@@ -58,7 +59,7 @@ public class UserConsoleElController {
@Function("user.update")
@PutMapping
public JsonResult update(@Validated(ValidateConfig.UPDATE.class) CoreUser user) {
public JsonResult update(@Validated(ValidateConfig.UPDATE.class) @RequestBody CoreUser user) {
boolean success = userConsoleService.updateTemplate(user);
if (success) {
this.platformService.clearFunctionCache();
......
......@@ -25,7 +25,7 @@ public class CoreUserElQuery {
isShowEditorPanel = false)
protected Long id;
@ElColumn(name = "创建时间", type = DATE)
@ElColumn(name = "创建时间", type = DATE, isShowEditorPanel = false)
protected Date createTime;
@ElColumn(name = "用户名", type = STRING, isShowSearchPanel = false)
......@@ -34,15 +34,20 @@ public class CoreUserElQuery {
@ElColumn(name = "姓名", type = STRING)
private String name;
@ElColumn(name = "机构", type = STRING)
@ElColumn(
name = "机构",
type = STRING,
jsonPath = "org.name",
isShowSearchPanel = false,
isShowEditorPanel = false)
private Long orgId;
@ElColumn(name = "状态", type = DICT)
@ElColumn(name = "状态", type = DICT, isShowEditorPanel = false)
private String state;
@ElColumn(name = "职务", type = DICT)
@ElColumn(name = "职务", type = DICT, isShowEditorPanel = false)
private String jobType0;
@ElColumn(name = "岗位", type = DICT)
@ElColumn(name = "岗位", type = DICT, isShowEditorPanel = false)
private String jobType1;
}
......@@ -24,6 +24,9 @@ and #function("user.query")#
@if(!isEmpty(jobType0)){
and u.job_type0= #jobType0#
@}
@if(!isEmpty(jobType1)){
and u.job_type1= #jobType1#
@}
@if(!isEmpty(createTimeStart)){
and u.create_time>= #createTimeStart#
@}
......@@ -31,6 +34,7 @@ and #function("user.query")#
and u.create_time< #nextDay(createTimeEnd)#
@}
```
@ mapping("UsersMapping");
batchDelUserByIds
===
......@@ -67,9 +71,9 @@ UsersMapping
===
```
var user_mapping_var={
"id": "core_route_map",
"id": "core_user_map",
"mapping": {
"resultType": "com.ibeetl.admin.core.entity.CoreRoute",
"resultType": "com.ibeetl.admin.core.entity.CoreUser",
"id": "id",
"createTime": "create_time",
"code": "code",
......
......@@ -189,7 +189,7 @@ public class CustomErrorController extends AbstractErrorController {
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┣━━━━ error fileds: <{}> ━━━━", errors))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("━━━━ error cause: <{}> ━━━━", cause))
.append(StrUtil.format("━━━━ error cause: <{}> ━━━━", cause))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┗━━━━ request path <{}> error log.━━━━", path));
logger.error(log.toString());
......
package com.ibeetl.admin.core.conf;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.PropertyNamingStrategy.SnakeCaseStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.ibeetl.admin.core.conf.jackson.serializer.CustomJsonResultSerializer;
import com.ibeetl.admin.core.conf.jackson.serializer.CustomLongSerializer;
import com.ibeetl.admin.core.conf.jackson.serializer.DateToTimestampSerializer;
import com.ibeetl.admin.core.conf.jackson.serializer.DictTypeEnumSerializer;
import com.ibeetl.admin.core.util.enums.DictTypeEnum;
import com.ibeetl.admin.core.web.JsonResult;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import org.beetl.sql.core.engine.PageQuery;
import java.util.Date;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/** @author 一日看尽长安花 */
@Configuration
public class JasonConfig {
public class JacksonConfig {
@Bean
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper getObjectMapper() {
......@@ -48,16 +33,17 @@ public class JasonConfig {
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
/*将date字段序列化为时间戳*/
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
/*map中date的也序列化为时间戳*/
objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, true);
/*将date字段序列化为时间戳,此转换会转成纳秒级*/
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
/*map中date的也序列化为时间戳,此转换会转成纳秒级*/
objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
SimpleModule simpleModule = new SimpleModule("SimpleModule", Version.unknownVersion());
simpleModule.addSerializer(JsonResult.class, new CustomJsonResultSerializer());
simpleModule.addSerializer(DictTypeEnum.class, new DictTypeEnumSerializer());
simpleModule.addSerializer(Date.class, new DateToTimestampSerializer());
CustomLongSerializer longSerializer = new CustomLongSerializer();
simpleModule.addSerializer(Long.class, longSerializer);
......@@ -68,85 +54,3 @@ public class JasonConfig {
}
}
class DictTypeEnumSerializer extends JsonSerializer<DictTypeEnum> {
@Override
public void serialize(DictTypeEnum value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
if (value instanceof Enum) {
gen.writeObjectField("name", ReflectUtil.getFieldValue(value, "name"));
gen.writeObjectField("value", ReflectUtil.getFieldValue(value, "value"));
gen.writeObjectField("type", ReflectUtil.getFieldValue(value, "type"));
}
gen.writeEndObject();
}
}
/**
* 修正jackson转换Long类型的一个bug: jackson的转换Long类型时,如果数值在Integer范围,会变成Integer类型,然后通过强制转换为Long时就会报错。
* 这里采用安全的Long转换避免强制类型转换
*/
class CustomLongSerializer extends StdSerializer<Object> {
CustomLongSerializer() {
super(Object.class);
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeNumber(Convert.toLong(value, null));
}
@Override
public void serializeWithType(
Object value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer)
throws IOException {
WritableTypeId typeIdDef =
typeSer.writeTypePrefix(g, typeSer.typeId(value, JsonToken.VALUE_NUMBER_INT));
serialize(value, g, provider);
typeSer.writeTypeSuffix(g, typeIdDef);
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
return createSchemaNode("long", true);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException {
visitIntFormat(visitor, typeHint, NumberType.LONG);
}
}
/**
* layui 前端要求后台返回的数据格式
*
* @author xiandafu
*/
class CustomJsonResultSerializer extends JsonSerializer<JsonResult> {
CustomJsonResultSerializer() {}
/** 处理 JsonResult 返回结果。自动分离分页信息,不需要手动在controller中分离 */
@Override
public void serialize(JsonResult value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeObjectField("code", Integer.parseInt(value.getCode()));
gen.writeStringField("message", value.getMessage());
Object data = value.getData();
if (data instanceof PageQuery) {
PageQuery query = (PageQuery) (data);
/*不同js前端插件会有不一样数据格式,所以返回两种命名*/
gen.writeNumberField("count", query.getTotalRow());
gen.writeNumberField("total", query.getTotalRow());
gen.writeObjectField("data", query.getList());
} else {
gen.writeObjectField("data", data);
}
gen.writeEndObject();
}
}
package com.ibeetl.admin.core.conf;
import static org.springframework.http.HttpMethod.DELETE;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.OPTIONS;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ibeetl.admin.core.annotation.RequestBodyPlus;
import com.ibeetl.admin.core.annotation.SnakeCaseParameter;
import com.ibeetl.admin.core.conf.springmvc.convert.DateConditionalGenericConverter;
import com.ibeetl.admin.core.conf.springmvc.convert.StringToDictTypeEnumConverFactory;
import com.ibeetl.admin.core.conf.springmvc.interceptor.HttpRequestInterceptor;
import com.ibeetl.admin.core.conf.springmvc.interceptor.SessionInterceptor;
import com.ibeetl.admin.core.conf.springmvc.resolve.RequestBodyPlusProcessor;
import com.ibeetl.admin.core.service.CoreUserService;
import com.ibeetl.admin.core.util.HttpRequestLocal;
import com.ibeetl.admin.core.util.JoseJwtUtil;
import com.ibeetl.admin.core.util.enums.DictTypeEnum;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.beetl.core.GroupTemplate;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.env.Environment;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
/** 切勿在此配置类中向SpringMVC中添加bean。 也就是不要 @Bean这类方法。 会出现无法ServletContext注入null,因为父接口的原因 */
......@@ -109,13 +81,15 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
registry
.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods(GET.name(), POST.name(), PUT.name(), DELETE.name(), OPTIONS.name());
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
// resolvers.add(new UnderlineToCamelArgumentResolver());
}
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
/**
* SpringMVC的请求响应消息的转换格式器
......@@ -126,71 +100,9 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
registry.addConverter(
new ConditionalGenericConverter() {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
boolean targetTypeMatches =
Optional.ofNullable(targetType.getResolvableType())
.map(ResolvableType::resolve)
.map(resolvableType -> resolvableType.equals(Date.class))
.orElse(false);
return targetTypeMatches;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CollUtil.newHashSet(
new ConvertiblePair(String.class, Date.class),
new ConvertiblePair(Long.class, Date.class));
}
@Override
public Object convert(
Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return DateUtil.date(Convert.toLong(source));
}
});
registry.addConverter(
new ConditionalGenericConverter() {
/**
* 处理从前端传递的字符串到对应的字典枚举,需要字典枚举类实现 {@link DictTypeEnum} 接口
*
* @return boolean
*/
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class targetClass =
Optional.ofNullable(targetType.getResolvableType())
.map(ResolvableType::resolve)
.orElse(null);
return sourceType.getResolvableType().resolve().equals(String.class)
&& Enum.class.isAssignableFrom(targetClass)
&& DictTypeEnum.class.isAssignableFrom(targetClass);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CollUtil.newHashSet(new ConvertiblePair(String.class, DictTypeEnum.class));
}
@Override
public Object convert(
Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
Class enumClass = targetType.getResolvableType().resolve();
Map<String, Object> valueFieldMap = EnumUtil.getNameFieldMap(enumClass, "value");
Set<Entry<String, Object>> entrySet = valueFieldMap.entrySet();
String targetEnumName = StrUtil.EMPTY;
for (Entry<String, Object> entry : entrySet) {
if (entry.getValue().equals(source.toString())) {
targetEnumName = entry.getKey();
break;
}
}
return EnumUtil.fromStringQuietly(enumClass, targetEnumName);
}
});
/*converter 在json传参时无效*/
registry.addConverterFactory(new StringToDictTypeEnumConverFactory());
registry.addConverter(new DateConditionalGenericConverter());
}
@Override
......@@ -210,173 +122,3 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
adapter.setArgumentResolvers(argumentResolvers);
}
}
class HttpRequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpRequestLocal.set(request);
return true;
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
HttpRequestLocal.destory();
}
}
class SessionInterceptor implements HandlerInterceptor {
CoreUserService userService;
public SessionInterceptor(CoreUserService userService) {
this.userService = userService;
}
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = HttpRequestLocal.getAuthorization();
boolean isExpiration = JoseJwtUtil.verifyJwtJson(token);
if (isExpiration) {
/*验证失败,无效jwt*/
return false;
} else {
token = JoseJwtUtil.refreshIssuedAtTime(token);
response.setHeader(HttpHeaders.AUTHORIZATION, token);
}
return true;
}
}
/** 自定义SpringMVC的controller方法的参数注解 {@link RequestBodyPlus} 的注入解析, 用json path 的方式注入json请求的参数 */
class RequestBodyPlusProcessor extends AbstractMessageConverterMethodProcessor {
private static final ThreadLocal<String> bodyLocal = ThreadLocal.withInitial(() -> "{}");
protected RequestBodyPlusProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBodyPlus.class);
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws Exception {
parameter = parameter.nestedIfOptional();
/*非json请求过滤*/
Class<?> parameterClass = parameter.getNestedParameterType();
if (!StrUtil.containsAny(
webRequest.getHeader(HttpHeaders.CONTENT_TYPE), MediaType.APPLICATION_JSON_VALUE)) {
return ReflectUtil.newInstanceIfPossible(parameterClass);
}
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
String jsonBody;
try {
String readBody = stringHttpMessageConverter.read(String.class, inputMessage);
/*每一个参数的注入都会读取一次输入流,但是request的输入流不可重复读,所以需要保持下来*/
if (StrUtil.isBlank(readBody)) {
jsonBody = bodyLocal.get();
} else {
bodyLocal.set(readBody);
jsonBody = bodyLocal.get();
}
} catch (IOException e) {
logger.error("Can't read request body by input stream : {}", e);
jsonBody = bodyLocal.get();
}
RequestBodyPlus requestBodyPlus = parameter.getParameterAnnotation(RequestBodyPlus.class);
JSON json = JSONUtil.parse(jsonBody);
Object parseVal = json.getByPath(requestBodyPlus.value(), parameterClass);
if (parseVal instanceof Map) {
JSONObject jsonObject = JSONUtil.parseObj(parseVal);
parseVal = JSONUtil.toBean(jsonObject, parameter.getNestedGenericParameterType(), true);
} else if (parseVal instanceof List) {
JSONArray jsonArray = JSONUtil.parseArray(parseVal);
Type parameterType = TypeUtil.getTypeArgument(parameter.getNestedGenericParameterType());
Class parameterTypeClass =
null == parameterType ? Object.class : ClassUtil.loadClass(parameterType.getTypeName());
parseVal = JSONUtil.toList(jsonArray, parameterTypeClass);
}
return parseVal;
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return false;
}
@Override
public void handleReturnValue(
Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) {}
}
/**
* Class UnderlineToCamelArgumentResolver : <br>
* 描述:处理请求参数的命名由下划线等转驼峰命名。<br>
* 但是与另一个{@link DictTypeEnum} 枚举处理有冲突,所以交给前端处理命名转换
*
* @author 一日看尽长安花 Created on 2020/2/2
*/
class UnderlineToCamelArgumentResolver implements HandlerMethodArgumentResolver {
/** 匹配下划线的格式 */
private static Pattern pattern = Pattern.compile("_(\\w)");
private static String underLineToCamel(String source) {
Matcher matcher = pattern.matcher(source);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
}
matcher.appendTail(sb);
return sb.toString();
}
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(SnakeCaseParameter.class);
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer container,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
return handleParameterNames(parameter, webRequest);
}
private Object handleParameterNames(MethodParameter parameter, NativeWebRequest webRequest) {
Object obj = BeanUtils.instantiateClass(parameter.getParameterType());
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
Iterator<String> paramNames = webRequest.getParameterNames();
while (paramNames.hasNext()) {
String paramName = paramNames.next();
Object o = webRequest.getParameter(paramName);
try {
wrapper.setPropertyValue(underLineToCamel(paramName), o);
} catch (BeansException e) {
}
}
return obj;
}
}
......@@ -19,6 +19,12 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
/**
* Class ServiceValidationAop : <br/>
* 描述:使用java validation规范对service层方法进行参数校验
* @author 一日看尽长安花
* Created on 2020/3/3
*/
@Aspect
@Component
public class ServiceValidationAop {
......
package com.ibeetl.admin.core.conf.beetl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibeetl.admin.core.conf.JasonConfig;
import com.ibeetl.admin.core.conf.JacksonConfig;
import com.ibeetl.admin.core.conf.beetl.handler.DateTypeHandler;
import com.ibeetl.admin.core.conf.beetl.handler.DictTypeHandler;
import com.ibeetl.admin.core.conf.beetl.handler.ZonedDateTimeTypeHandler;
......@@ -55,7 +53,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
@AutoConfigureAfter(JasonConfig.class)
@AutoConfigureAfter(JacksonConfig.class)
public class BeetlConf {
@Autowired Environment env;
@Autowired CorePlatformService platFormService;
......
package com.ibeetl.admin.core.conf.beetl.resultmap;
import static cn.hutool.core.util.StrUtil.EMPTY;
import static cn.hutool.core.util.StrUtil.isNotBlank;
import static java.util.Optional.ofNullable;
......@@ -15,7 +14,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
/**
......
package com.ibeetl.admin.core.conf.jackson.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.ibeetl.admin.core.web.JsonResult;
import java.io.IOException;
import org.beetl.sql.core.engine.PageQuery;
/**
* layui 前端要求后台返回的数据格式
*
* @author xiandafu
*/
public class CustomJsonResultSerializer extends JsonSerializer<JsonResult> {
public CustomJsonResultSerializer() {}
/** 处理 JsonResult 返回结果。自动分离分页信息,不需要手动在controller中分离 */
@Override
public void serialize(JsonResult value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeObjectField("code", Integer.parseInt(value.getCode()));
gen.writeStringField("message", value.getMessage());
Object data = value.getData();
if (data instanceof PageQuery) {
PageQuery query = (PageQuery) (data);
/*不同js前端插件会有不一样数据格式,所以返回两种命名*/
gen.writeNumberField("count", query.getTotalRow());
gen.writeNumberField("total", query.getTotalRow());
gen.writeObjectField("data", query.getList());
} else {
gen.writeObjectField("data", data);
}
gen.writeEndObject();
}
}
package com.ibeetl.admin.core.conf.jackson.serializer;
import cn.hutool.core.convert.Convert;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.lang.reflect.Type;
/**
* 修正jackson转换Long类型的一个bug: jackson的转换Long类型时,如果数值在Integer范围,会变成Integer类型,然后通过强制转换为Long时就会报错。
* 这里采用安全的Long转换避免强制类型转换
*/
public class CustomLongSerializer extends StdSerializer<Object> {
public CustomLongSerializer() {
super(Object.class);
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeNumber(Convert.toLong(value, null));
}
@Override
public void serializeWithType(
Object value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer)
throws IOException {
WritableTypeId typeIdDef =
typeSer.writeTypePrefix(g, typeSer.typeId(value, JsonToken.VALUE_NUMBER_INT));
serialize(value, g, provider);
typeSer.writeTypeSuffix(g, typeIdDef);
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
return createSchemaNode("long", true);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException {
visitIntFormat(visitor, typeHint, NumberType.LONG);
}
}
package com.ibeetl.admin.core.conf.jackson.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Date;
public class DateToTimestampSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeNumber(value.getTime()/1000L);
}
}
package com.ibeetl.admin.core.conf.jackson.serializer;
import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.ibeetl.admin.core.util.enums.DictTypeEnum;
import java.io.IOException;
public class DictTypeEnumSerializer extends JsonSerializer<DictTypeEnum> {
@Override
public void serialize(DictTypeEnum value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
if (value instanceof Enum) {
gen.writeObjectField("name", ReflectUtil.getFieldValue(value, "name"));
gen.writeObjectField("value", ReflectUtil.getFieldValue(value, "value"));
gen.writeObjectField("type", ReflectUtil.getFieldValue(value, "type"));
}
gen.writeEndObject();
}
}
package com.ibeetl.admin.core.conf.springmvc.convert;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import java.util.Date;
import java.util.Optional;
import java.util.Set;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
/**
* Class DateConditionalGenericConverter : <br/>
* 描述:时间戳转日期{@link Date} ,由于前端可能传字符串的时间戳,所以用了这个条件转换器
* @author 一日看尽长安花
* Created on 2020/3/9
*/
public class DateConditionalGenericConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
boolean targetTypeMatches =
Optional.ofNullable(targetType.getResolvableType())
.map(ResolvableType::resolve)
.map(resolvableType -> resolvableType.equals(Date.class))
.orElse(false);
return targetTypeMatches;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CollUtil.newHashSet(
new ConvertiblePair(String.class, Date.class), new ConvertiblePair(Long.class, Date.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return DateUtil.date(Convert.toLong(source));
}
}
package com.ibeetl.admin.core.conf.springmvc.convert;
import cn.hutool.core.map.MapUtil;
import com.ibeetl.admin.core.util.enums.DictTypeEnum;
import java.util.Map;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
public class StringToDictTypeEnumConverFactory implements ConverterFactory<String, DictTypeEnum> {
private static final Map<Class, Converter> CONVERTERS = MapUtil.newHashMap();
/**
* 获取一个从 Integer 转化为 T 的转换器,T 是一个泛型,有多个实现
*
* @param targetType 转换后的类型
* @return 返回一个转化器
*/
@Override
public <T extends DictTypeEnum> Converter<String, T> getConverter(Class<T> targetType) {
Converter<String, T> converter = CONVERTERS.get(targetType);
if (converter == null) {
converter = new StringToDictTypeEnumConvert(targetType);
CONVERTERS.put(targetType, converter);
}
return converter;
}
}
package com.ibeetl.admin.core.conf.springmvc.convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ibeetl.admin.core.util.enums.DictTypeEnum;
import java.util.Map;
import org.springframework.core.convert.converter.Converter;
public class StringToDictTypeEnumConvert<T extends DictTypeEnum> implements Converter<String, T> {
private Map<String, T> enumMap = MapUtil.newHashMap();
public StringToDictTypeEnumConvert(Class<T> enumType) {
T[] enums = enumType.getEnumConstants();
for (T e : enums) {
enumMap.put(e.getValue(), e);
}
}
@Override
public T convert(String source) {
T t = enumMap.get(source);
if (ObjectUtil.isNull(t)) {
throw new IllegalArgumentException("无法匹配对应的枚举类型");
}
return t;
}
}
package com.ibeetl.admin.core.conf.springmvc.interceptor;
import com.ibeetl.admin.core.util.HttpRequestLocal;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class HttpRequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpRequestLocal.set(request);
return true;
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
HttpRequestLocal.destory();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment