fix: 调整项目路径

This commit is contained in:
han0
2023-10-13 16:40:37 +08:00
parent 83ee2a8125
commit 63144e4911
15 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
package mjkf.xinke;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* SpringBoot方式启动类
*
*
* @date 2021/12/18 16:57
*/
@Slf4j
@EnableSwagger2WebMvc
@RestController
@SpringBootApplication
public class Application {
/* 解决druid 日志报错discard long time none received connection:xxx */
static {
System.setProperty("druid.mysql.usePingMethod","false");
}
/**
* 主启动函数
*
*
* @date 2022/7/30 21:42
*/
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);
log.info(">>> {}", Application.class.getSimpleName().toUpperCase() + " STARTING SUCCESS");
}
/**
* 首页
*
*
* @date 2022/7/8 14:22
**/
@GetMapping("/")
public String index() {
return "WELCOME";
}
}

View File

@@ -0,0 +1,65 @@
package mjkf.xinke.core.config;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import java.io.IOException;
/**
* druid配置
*
* @author diantu
* @date 2023/06/30
**/
@Configuration
public class DruidConfigure {
/**
* 去除druid监控页面广告
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties)
{
// 获取web监控页面的参数
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路径
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
// 创建filter进行过滤
Filter filter = new Filter()
{
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
chain.doFilter(request, response);
// 重置缓冲区,响应头不会被重置
response.resetBuffer();
// 获取common.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
response.getWriter().write(text);
}
@Override
public void destroy()
{
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}

View File

@@ -0,0 +1,618 @@
package mjkf.xinke.core.config;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectionException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import mjkf.xinke.auth.core.util.StpClientUtil;
import mjkf.xinke.common.annotation.CommonNoRepeat;
import mjkf.xinke.common.annotation.CommonWrapper;
import mjkf.xinke.common.cache.CommonCacheOperator;
import mjkf.xinke.common.enums.CommonDeleteFlagEnum;
import mjkf.xinke.common.exception.CommonException;
import mjkf.xinke.common.listener.CommonDataChangeEventCenter;
import mjkf.xinke.common.listener.CommonDataChangeListener;
import mjkf.xinke.common.pojo.CommonResult;
import mjkf.xinke.common.pojo.CommonWrapperInterface;
import mjkf.xinke.common.util.CommonTimeFormatUtil;
import mjkf.xinke.core.handler.GlobalExceptionUtil;
import mjkf.xinke.sys.core.enums.SysBuildInEnum;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
/**
* Snowy配置
*
*
* @date 2021/10/9 14:24
**/
@Configuration
@MapperScan(basePackages = {"mjkf.xinke.**.mapper, com.bstek.**.mapper"})
public class GlobalConfigure implements WebMvcConfigurer {
private static final String COMMON_REPEAT_SUBMIT_CACHE_KEY = "common-repeatSubmit:";
@Resource
private CommonCacheOperator commonCacheOperator;
/**
* 无需登录的接口地址集合
*/
private static final String[] NO_LOGIN_PATH_ARR = {
/* 主入口 */
"/",
/* 静态资源 */
"/favicon.ico",
"/doc.html",
"/webjars/**",
"/swagger-resources/**",
"/v2/api-docs",
"/v2/api-docs-ext",
"/configuration/ui",
"/configuration/security",
"/ureport/**",
"/druid/**",
"/images/**",
/* 认证相关 */
"/auth/c/getPicCaptcha",
"/auth/c/getPhoneValidCode",
"/auth/c/doLogin",
"/auth/c/doLoginByPhone",
"/auth/b/getPicCaptcha",
"/auth/b/getPhoneValidCode",
"/auth/b/doLogin",
"/auth/b/doLoginByPhone",
/* 三方登录相关 */
"/auth/third/render",
"/auth/third/callback",
/* 系统基础配置 */
"/dev/config/sysBaseList",
/* 系统字典树 */
"/dev/dict/tree",
/* 文件下载 */
"/dev/file/download",
/* 用户个人中心相关 */
"/sys/userCenter/getPicCaptcha",
"/sys/userCenter/findPasswordGetPhoneValidCode",
"/sys/userCenter/findPasswordGetEmailValidCode",
"/sys/userCenter/findPasswordByPhone",
"/sys/userCenter/findPasswordByEmail",
/* 租户选择器*/
"/ten/storage/tenSelector",
/* 支付相关回调通知 */
"/pay/ali/notifyUrl",
"/pay/wx/notifyUrl",
"/pay/wx/authNotifyUrl",
"/pay/wx/jsPay",
"/pay/order/sample/doCreateOrder",
};
/**
* 仅超管使用的接口地址集合
*/
private static final String[] SUPER_PERMISSION_PATH_ARR = {
"/auth/session/**",
"/auth/third/page",
"/client/user/**",
"/sys/org/**",
"/sys/position/**",
"/sys/button/**",
"/sys/menu/**",
"/sys/module/**",
"/sys/spa/**",
"/sys/role/**",
"/sys/user/**",
"/dev/config/**",
"/dev/dict/**",
"/dev/email/page",
"/dev/email/delete",
"/dev/email/detail",
"/dev/file/page",
"/dev/file/list",
"/dev/file/delete",
"/dev/file/detail",
"/dev/job/**",
"/dev/log/**",
"/dev/message/page",
"/dev/message/delete",
"/dev/message/detail",
"/dev/monitor/**",
"/dev/sms/page",
"/dev/sms/delete",
"/dev/sms/detail",
"/gen/basic/**",
"/gen/config/**",
"/mobile/menu/**",
"/mobile/module/**",
"/flw/model/**",
"/flw/templatePrint/**",
"/flw/templateSn/**",
"/pay/**",
"/urp/**",
"/dbs/**",
"/ten/"
};
/**
* B端要排除的相当于C端要认证的
*/
private static final String[] CLIENT_USER_PERMISSION_PATH_ARR = {
"/auth/c/**",
"/client/c/**"
};
/**
* 注册跨域过滤器
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
// 指定拦截路由
.addInclude("/**")
// 设置鉴权的接口
.setAuth(r -> {
// B端的接口校验B端登录
SaRouter.match("/**")
// 排除无需登录接口
.notMatch(CollectionUtil.newArrayList(NO_LOGIN_PATH_ARR))
// 排除C端认证接口
.notMatch(CollectionUtil.newArrayList(CLIENT_USER_PERMISSION_PATH_ARR))
// 校验B端登录
.check(r1 -> StpUtil.checkLogin());
// C端的接口校验C端登录
SaRouter.match("/**")
// 排除无需登录接口
.notMatch(CollectionUtil.newArrayList(NO_LOGIN_PATH_ARR))
// 匹配C端认证接口
.match(CollectionUtil.newArrayList(CLIENT_USER_PERMISSION_PATH_ARR))
// 校验C端登录
.check(r1 -> StpClientUtil.checkLogin());
// B端的超管接口校验B端超管角色
SaRouter.match("/**")
// 排除无需登录接口
.notMatch(CollectionUtil.newArrayList(NO_LOGIN_PATH_ARR))
// 匹配超管接口
.match(CollectionUtil.newArrayList(SUPER_PERMISSION_PATH_ARR))
// 校验B端超管角色
.check(r1 -> StpUtil.checkRole(SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue()));
})
// 前置函数:在每次认证函数之前执行
.setBeforeAuth(obj -> {
// ---------- 设置跨域响应头 ----------
SaHolder.getResponse()
// 是否可以在iframe显示视图 DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
// .setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否启用浏览器默认XSS防护 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时停止渲染页面
.setHeader("X-XSS-Protection", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
// 允许指定域访问跨域资源
.setHeader("Access-Control-Allow-Origin", "*")
// 允许所有请求方式
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
// 有效时间
.setHeader("Access-Control-Max-Age", "3600")
// 允许的header参数
.setHeader("Access-Control-Allow-Headers", "*");
// 如果是预检请求,则立即返回到前端
SaRouter.match(SaHttpMethod.OPTIONS)
// OPTIONS预检请求不做处理
.free(r -> {})
.back();
})
// 异常处理
.setError(e -> {
// 由于过滤器中抛出的异常不进入全局异常处理,所以必须提供[异常处理函数]来处理[认证函数]里抛出的异常
// 在[异常处理函数]里的返回值将作为字符串输出到前端此处统一转为JSON输出前端
SaResponse saResponse = SaHolder.getResponse();
saResponse.setHeader(Header.CONTENT_TYPE.getValue(), ContentType.JSON + ";charset=" + CharsetUtil.UTF_8);
return GlobalExceptionUtil.getCommonResult((Exception) e);
});
}
/**
* RedisTemplate序列化
*
*
* @date 2022/6/21 17:01
**/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 静态资源映射
*
*
* @date 2022/7/25 15:16
**/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/ureport/res/**").addResourceLocations("classpath:/META-INF/resources/ureport-asserts/");
}
/**
* 添加节流防抖拦截器
*
*
* @date 2022/6/20 15:18
**/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
@NonNull Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
CommonNoRepeat annotation = method.getAnnotation(CommonNoRepeat.class);
if (ObjectUtil.isNotEmpty(annotation)) {
JSONObject repeatSubmitJsonObject = this.isRepeatSubmit(request, annotation);
if (repeatSubmitJsonObject.getBool("repeat")) {
response.setCharacterEncoding(CharsetUtil.UTF_8);
response.setContentType(ContentType.JSON.toString());
response.getWriter().write(JSONUtil.toJsonStr(CommonResult.error("请求过于频繁,请" + repeatSubmitJsonObject.getStr("time") + "后再试")));
return false;
}
}
}
return true;
}
public JSONObject isRepeatSubmit(HttpServletRequest request, CommonNoRepeat annotation) {
JSONObject jsonObject = JSONUtil.createObj();
jsonObject.set("repeatParam", JSONUtil.toJsonStr(request.getParameterMap()));
jsonObject.set("repeatTime", DateUtil.current());
String url = request.getRequestURI();
// 获取该接口缓存的限流数据
Object cacheObj = commonCacheOperator.get(COMMON_REPEAT_SUBMIT_CACHE_KEY + url);
if (ObjectUtil.isNotEmpty(cacheObj)) {
JSONObject cacheJsonObject = JSONUtil.parseObj(cacheObj);
if(cacheJsonObject.containsKey(url)) {
JSONObject existRepeatJsonObject = cacheJsonObject.getJSONObject(url);
// 如果与上次参数一致,且时间间隔小于要求的限流时长,则判定为重复提交
if (jsonObject.getStr("repeatParam").equals(existRepeatJsonObject.getStr("repeatParam"))) {
long interval = jsonObject.getLong("repeatTime") - existRepeatJsonObject.getLong("repeatTime");
if(interval < annotation.interval()) {
long secondsParam = (annotation.interval() - interval) / 1000;
if(secondsParam == 0) {
return JSONUtil.createObj().set("repeat", false);
} else {
return JSONUtil.createObj().set("repeat", true).set("time", CommonTimeFormatUtil.formatSeconds(secondsParam));
}
}
}
}
}
// 缓存最新的该接口的限流数据为防止缓存的数据过多缓存时效为1小时
commonCacheOperator.put(COMMON_REPEAT_SUBMIT_CACHE_KEY + url, JSONUtil.createObj().set(url, jsonObject), 60 * 60);
return JSONUtil.createObj().set("repeat", false);
}
}).addPathPatterns("/**");
}
/**
* 通用Wrapper的AOP
*
*
* @date 2022/9/15 21:24
*/
@Component
@Aspect
public static class CommonWrapperAop {
/**
* 切入点
*
*
* @date 2022/9/15 21:27
*/
@Pointcut("@annotation(mjkf.xinke.common.annotation.CommonWrapper)")
private void wrapperPointcut() {
}
/**
* 执行包装
*
*
* @date 2022/9/15 21:27
*/
@Around("wrapperPointcut()")
public Object doWrapper(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 直接执行原有业务逻辑
Object proceedResult = proceedingJoinPoint.proceed();
return processWrapping(proceedingJoinPoint, proceedResult);
}
/**
* 具体包装过程
*
*
* @date 2022/9/15 21:27
*/
@SuppressWarnings("all")
private Object processWrapping(ProceedingJoinPoint proceedingJoinPoint, Object originResult) throws IllegalAccessException, InstantiationException {
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
CommonWrapper commonWrapper = method.getAnnotation(CommonWrapper.class);
Class<? extends CommonWrapperInterface<?>>[] baseWrapperClasses = commonWrapper.value();
if (ObjectUtil.isEmpty(baseWrapperClasses)) {
return originResult;
}
if (!(originResult instanceof CommonResult)) {
return originResult;
}
CommonResult commonResult = (CommonResult) originResult;
Object beWrapped = commonResult.getData();
if (ObjectUtil.isBasicType(beWrapped)) {
throw new CommonException("被包装的值不能是基本类型");
}
if (beWrapped instanceof Page) {
Page page = (Page) beWrapped;
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : page.getRecords()) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
page.setRecords(maps);
commonResult.setData(page);
} else if (beWrapped instanceof Collection) {
Collection collection = (Collection) beWrapped;
List<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : collection) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
commonResult.setData(maps);
} else if (ArrayUtil.isArray(beWrapped)) {
Object[] objects = this.objToArray(beWrapped);
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : objects) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
commonResult.setData(maps);
} else {
commonResult.setData(this.wrapPureObject(beWrapped, baseWrapperClasses));
}
return commonResult;
}
/**
* 原始对象包装JSONObject
*
*
* @date 2022/9/15 21:36
*/
@SuppressWarnings("all")
private JSONObject wrapPureObject(Object originModel, Class<? extends CommonWrapperInterface<?>>[] baseWrapperClasses) {
JSONObject jsonObject = JSONUtil.parseObj(originModel);
try {
for (Class<? extends CommonWrapperInterface<?>> commonWrapperClass : baseWrapperClasses) {
CommonWrapperInterface commonWrapperInterface = commonWrapperClass.newInstance();
Map<String, Object> incrementFieldsMap = commonWrapperInterface.doWrap(originModel);
jsonObject.putAll(incrementFieldsMap);
}
} catch (Exception e) {
throw new CommonException("原始对象包装过程,字段转化异常:{}", e.getMessage());
}
return jsonObject;
}
/**
* Object转array
*
*
* @date 2022/9/15 21:34
*/
private Object[] objToArray(Object object) {
int length = Array.getLength(object);
Object[] result = new Object[length];
for (int i = 0; i < result.length; i++) {
result[i] = Array.get(object, i);
}
return result;
}
}
/**
* 数据库id选择器用于Mapper.xml中
* MyBatis可以根据不同的数据库厂商执行不同的语句
*
*
* @date 2022/1/8 2:16
*/
@Component
public static class CustomDbIdProvider implements DatabaseIdProvider {
@Override
public String getDatabaseId(DataSource dataSource) throws SQLException {
Connection conn = null;
try {
conn = dataSource.getConnection();
String url = conn.getMetaData().getURL().toLowerCase();
if (url.contains("jdbc:oracle")) {
return "oracle";
} else if (url.contains("jdbc:postgresql")) {
return "pgsql";
} else if (url.contains("jdbc:mysql")) {
return "mysql";
} else if (url.contains("jdbc:dm")) {
return "dm";
} else if (url.contains("jdbc:kingbase")) {
return "kingbase";
} else {
return "mysql";
}
} finally {
JdbcUtils.closeConnection(conn);
}
}
}
/**
* 自定义公共字段自动注入
*
*
* @date 2020/3/31 15:42
*/
@Component
public static class CustomMetaObjectHandler implements MetaObjectHandler {
/** 删除标志 */
private static final String DELETE_FLAG = "deleteFlag";
/** 创建人 */
private static final String CREATE_USER = "createUser";
/** 创建时间 */
private static final String CREATE_TIME = "createTime";
/** 更新人 */
private static final String UPDATE_USER = "updateUser";
/** 更新时间 */
private static final String UPDATE_TIME = "updateTime";
@Override
public void insertFill(MetaObject metaObject) {
try {
//为空则设置deleteFlag
Object deleteFlag = metaObject.getValue(DELETE_FLAG);
if (ObjectUtil.isNull(deleteFlag)) {
setFieldValByName(DELETE_FLAG, EnumUtil.toString(CommonDeleteFlagEnum.NOT_DELETE), metaObject);
}
} catch (ReflectionException ignored) { }
try {
//为空则设置createUser
Object createUser = metaObject.getValue(CREATE_USER);
if (ObjectUtil.isNull(createUser)) {
setFieldValByName(CREATE_USER, this.getUserId(), metaObject);
}
} catch (ReflectionException ignored) { }
try {
//为空则设置createTime
Object createTime = metaObject.getValue(CREATE_TIME);
if (ObjectUtil.isNull(createTime)) {
setFieldValByName(CREATE_TIME, DateTime.now(), metaObject);
}
} catch (ReflectionException ignored) { }
}
@Override
public void updateFill(MetaObject metaObject) {
try {
//设置updateUser
setFieldValByName(UPDATE_USER, this.getUserId(), metaObject);
} catch (ReflectionException ignored) { }
try {
//设置updateTime
setFieldValByName(UPDATE_TIME, DateTime.now(), metaObject);
} catch (ReflectionException ignored) { }
}
/**
* 获取用户id
*/
private String getUserId() {
try {
String loginId = StpUtil.getLoginIdAsString();
if (ObjectUtil.isNotEmpty(loginId)) {
return loginId;
} else {
return "-1";
}
} catch (Exception e) {
return "-1";
}
}
}
/**
* 注册数据变化事件中心 事件发布器
*
*
* @date 2023/3/3 14:27
**/
@Resource
public void registerListenerList(List<CommonDataChangeListener> dataChangeListenerList) {
CommonDataChangeEventCenter.registerListenerList(dataChangeListenerList);
}
}

View File

@@ -0,0 +1,64 @@
package mjkf.xinke.core.handler;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
import mjkf.xinke.common.exception.CommonException;
import mjkf.xinke.common.pojo.CommonResult;
import mjkf.xinke.common.util.CommonServletUtil;
import java.util.Map;
/**
* 将未知错误异常,输出格式重写为我们熟悉的响应格式
*
*
* @date 2021/10/9 15:24
**/
@Component
public class GlobalErrorAttributesHandler extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions attributeOptions) {
// 获取spring默认的返回内容
Map<String, Object> defaultErrorAttributes = super.getErrorAttributes(webRequest, attributeOptions);
// 获取其状态码
Object status = defaultErrorAttributes.get("status");
if (ObjectUtil.isNotEmpty(status)) {
// 如果其为404则处理
if (HttpStatus.HTTP_NOT_FOUND == Convert.toInt(status)) {
Object path = defaultErrorAttributes.get("path");
if(ObjectUtil.isNotEmpty(path)) {
return BeanUtil.beanToMap(CommonResult.get(HttpStatus.HTTP_NOT_FOUND, "路径不存在,请求地址:" +
Convert.toStr(path), null));
} else {
return BeanUtil.beanToMap(CommonResult.get(HttpStatus.HTTP_NOT_FOUND, "路径不存在", null));
}
} else {
return BeanUtil.beanToMap(CommonResult.get(HttpStatus.HTTP_INTERNAL_ERROR, "服务器异常,请求地址:" +
CommonServletUtil.getRequest().getRequestURL(), null));
}
}
// 如果返回的异常是CommonException则按CommonException响应的内容进行返回
Throwable throwable = this.getError(webRequest);
if (ObjectUtil.isNotEmpty(throwable)) {
if (throwable instanceof CommonException) {
CommonException commonException = (CommonException) throwable;
return BeanUtil.beanToMap(CommonResult.error(commonException.getMsg()));
} else {
return BeanUtil.beanToMap(CommonResult.get(HttpStatus.HTTP_INTERNAL_ERROR, "服务器异常,请求地址:" +
CommonServletUtil.getRequest().getRequestURL(), null));
}
} else {
// throwable为空则直接返回默认异常
return BeanUtil.beanToMap(CommonResult.error());
}
}
}

View File

@@ -0,0 +1,58 @@
package mjkf.xinke.core.handler;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import mjkf.xinke.common.exception.CommonException;
import mjkf.xinke.common.pojo.CommonResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 全局异常页面处理器覆盖默认的Whitelabel Error Page
*
*
* @date 2022/2/11 15:41
**/
@Slf4j
@RestController
public class GlobalErrorViewController {
/**
* Error页面视图直接响应JSON
*
*
* @date 2022/2/11 16:11
**/
@RequestMapping("/errorView")
public CommonResult<String> globalError(HttpServletRequest request, HttpServletResponse response) throws IOException {
CommonResult<String> commonResult = new CommonResult<>(404, "路径不存在", null);
Object model = request.getAttribute("model");
if(ObjectUtil.isNotEmpty(model)) {
if(model instanceof Exception){
if(model instanceof CommonException) {
JSONObject errorObj = JSONUtil.parseObj(model);
Integer code = errorObj.getInt("code");
String msg = errorObj.getStr("msg");
if(ObjectUtil.isAllNotEmpty(code, msg)) {
commonResult.setCode(code).setMsg(msg);
} else if(ObjectUtil.isNotEmpty(msg)) {
commonResult = CommonResult.error(msg);
} else {
commonResult = CommonResult.error();
}
} else {
commonResult = CommonResult.error();
log.error(">>> 服务器未知异常,具体信息:", (Exception) model);
}
}
}
return commonResult;
}
}

View File

@@ -0,0 +1,62 @@
package mjkf.xinke.core.handler;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Map;
/**
* 全局异常页面处理器覆盖默认的Whitelabel Error Page
*
*
* @date 2022/2/11 15:41
**/
@RestController
public class GlobalErrorViewHandler extends BasicErrorController {
public GlobalErrorViewHandler(ServerProperties serverProperties) {
super(new GlobalErrorAttributesHandler(), serverProperties.getError());
}
/**
* 覆盖默认的Json响应
*
*
* @date 2022/2/11 15:47
**/
@Override
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> defaultErrorAttributes = super.getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
Integer code = Convert.toInt(defaultErrorAttributes.get("code"));
return new ResponseEntity<>(defaultErrorAttributes, HttpStatus.valueOf(ObjectUtil.isNotEmpty(code)?code:500));
}
/**
* 覆盖默认的错误页面响应JSON
*
*
* @date 2022/2/12 21:55
*/
@Override
@RequestMapping(produces = {"text/html"})
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
request.setAttribute("model", model);
return modelAndView != null ? modelAndView : new ModelAndView("errorView", model);
}
}

View File

@@ -0,0 +1,29 @@
package mjkf.xinke.core.handler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import mjkf.xinke.common.pojo.CommonResult;
/**
* 全局异常处理器
*
*
* @date 2021/10/9 14:59
**/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 不同异常返回不同结果
*
*
* @date 2022/7/28 16:54
**/
@ResponseBody
@ExceptionHandler
public CommonResult<String> handleException(Exception e) {
return GlobalExceptionUtil.getCommonResult(e);
}
}

View File

@@ -0,0 +1,179 @@
package mjkf.xinke.core.handler;
import cn.dev33.satoken.exception.SaTokenException;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import mjkf.xinke.auth.core.util.AuthExceptionUtil;
import mjkf.xinke.common.exception.CommonException;
import mjkf.xinke.common.pojo.CommonResult;
import mjkf.xinke.common.util.CommonServletUtil;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
/**
* 全局异常处理工具类,将异常转为通用结果
*
*
* @date 2021/12/18 16:44
*/
@Slf4j
public class GlobalExceptionUtil {
/**
* 根据错误类型获取对应的CommonResult
*
*
* @date 2021/10/11 15:52
**/
public static CommonResult<String> getCommonResult(Exception e) {
CommonResult<String> commonResult;
if (e instanceof HttpRequestMethodNotSupportedException) {
// 如果是请求方法异常 405
String method = CommonServletUtil.getRequest().getMethod();
if (HttpMethod.GET.toString().equals(method)) {
commonResult = CommonResult.get(HttpStatus.HTTP_BAD_METHOD, "请求方法应为POST", null);
} else if(HttpMethod.POST.toString().equals(method)) {
commonResult = CommonResult.get(HttpStatus.HTTP_BAD_METHOD, "请求方法应为GET", null);
} else {
commonResult = CommonResult.get(HttpStatus.HTTP_BAD_METHOD, "请求方法仅支持GET或POST", null);
}
} else if (e instanceof HttpMessageNotReadableException) {
log.error(">>> 参数传递格式异常:", e);
// 如果是参数传递格式不支持异常 415
if (e.getMessage().contains("JSON parse error")) {
//JSON格式转换错误特殊提示
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, "参数格式错误", null);
} else {
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, "请使用JSON方式传参", null);
}
} else if (e instanceof HttpMediaTypeNotSupportedException) {
log.error(">>> 参数传递格式异常:", e);
// 如果是JSON参数格式错误异常 415
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, "参数格式错误", null);
} else if (e instanceof MethodArgumentNotValidException) {
// 如果是参数校验异常MethodArgumentNotValidException 415
MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) e;
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, getArgNotValidMessage(methodArgumentNotValidException.getBindingResult()), null);
} else if (e instanceof BindException) {
// 如果是参数校验异常BindException 415
BindException bindException = (BindException) e;
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, getArgNotValidMessage(bindException.getBindingResult()), null);
} else if (e instanceof ConstraintViolationException) {
// 如果是参数校验异常ConstraintViolationException 415
ConstraintViolationException constraintViolationException = (ConstraintViolationException) e;
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, getArgNotValidMessage(constraintViolationException.getConstraintViolations()), null);
} else if (e instanceof MissingServletRequestParameterException) {
// 如果是参数校验异常MissingServletRequestParameterException 415
MissingServletRequestParameterException missingServletRequestParameterException = (MissingServletRequestParameterException) e;
commonResult = CommonResult.get(HttpStatus.HTTP_UNSUPPORTED_TYPE, missingServletRequestParameterException.getMessage(), null);
}
else if (e instanceof MultipartException) {
log.error(">>> 文件上传参数异常:", e);
//文件上传错误特殊提示
commonResult = CommonResult.error("请使用multipart/form-data方式上传文件");
} else if (e instanceof MissingServletRequestPartException) {
log.error(">>> 文件上传参数异常:", e);
//文件上传错误特殊提示
commonResult = CommonResult.error("请选择要上传的文件并检查文件参数名称是否正确");
} else if (e instanceof SaTokenException) {
// 如果是SaToken相关异常则由AuthExceptionUtil处理
return AuthExceptionUtil.getCommonResult(e);
} else if(e instanceof MyBatisSystemException) {
// 如果是MyBatisSystemException
Throwable cause = e.getCause();
if (cause instanceof PersistenceException) {
Throwable secondCause = cause.getCause();
if (secondCause instanceof CommonException) {
CommonException commonException = (CommonException) secondCause;
commonResult = CommonResult.get(commonException.getCode(), commonException.getMsg(), null);
} else {
log.error(">>> 数据操作异常:", e);
commonResult = CommonResult.error("数据操作异常");
}
}else {
log.error(">>> 数据操作异常:", e);
commonResult = CommonResult.error("数据操作异常");
}
} else if (e instanceof CommonException) {
// 通用业务异常,直接返回给前端
CommonException commonException = (CommonException) e;
commonResult = CommonResult.get(commonException.getCode(), commonException.getMsg(), null);
} else {
// 未知异常打印详情
log.error(">>> 服务器未知异常,请求地址:{},具体信息:", CommonServletUtil.getRequest().getRequestURL(), e);
// 未知异常返回服务器异常
commonResult = CommonResult.error();
}
return commonResult;
}
/**
* 获取请求参数不正确的提示信息,多个信息,拼接成用逗号分隔的形式
*
*
* @date 2021/10/12 11:14
**/
public static String getArgNotValidMessage(Set<ConstraintViolation<?>> constraintViolationSet) {
if (ObjectUtil.isEmpty(constraintViolationSet)) {
return "";
}
StringBuilder stringBuilder = StrUtil.builder();
// 多个错误用逗号分隔
for (ConstraintViolation<?> constraintViolation : constraintViolationSet) {
stringBuilder.append(StrUtil.COMMA).append(constraintViolation.getMessage());
}
// 最终把首部的逗号去掉
return StrUtil.removePrefix(stringBuilder.toString(), StrUtil.COMMA);
}
/**
* 获取请求参数不正确的提示信息,多个信息,拼接成用逗号分隔的形式
*
*
* @date 2021/10/12 11:14
**/
public static String getArgNotValidMessage(BindingResult bindingResult) {
if (ObjectUtil.isNull(bindingResult)) {
return "";
}
StringBuilder stringBuilder = StrUtil.builder();
// 多个错误用逗号分隔
List<ObjectError> allErrorInfos = bindingResult.getAllErrors();
for (ObjectError error : allErrorInfos) {
stringBuilder.append(StrUtil.COMMA).append(error.getDefaultMessage());
}
// 最终把首部的逗号去掉
return StrUtil.removePrefix(stringBuilder.toString(), StrUtil.COMMA);
}
}

View File

@@ -0,0 +1,33 @@
{
"properties": [
{
"name": "mjkf-xinke.config.global.front-url",
"type": "java.lang.String",
"description": "前端地址."
},
{
"name": "mjkf-xinke.config.global.backend-url",
"type": "java.lang.String",
"description": "后端地址."
},
{
"name": "mjkf-xinke.config.ten.enabled",
"type": "java.lang.String",
"description": "是否开启多租户."
},
{
"name": "mjkf-xinke.config.ten.ignore-table-names",
"type": "java.lang.String",
"description": "租户id隔离的租户模式下需要忽略拼接租户id字段的表名称逗号分割."
},
{
"name": "mjkf-xinke.config.ten.ten-id-column-name",
"type": "java.lang.String",
"description": "租户id隔离的租户模式下租户字段名称数据表需具备对应字段名称."
},
{
"name": "mjkf-xinke.config.ten.default-ten-id",
"type": "java.lang.String",
"description": "租户id隔离的租户模式下默认租户ID."
}
] }

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,129 @@
camunda:
bpm:
auto-deployment-enabled: false
database:
schema-update: true
eventing:
history: false
job-execution:
enabled: false
metrics:
enabled: false
easy-trans:
is-enable-global: true
is-enable-redis: true
is-enable-tile: true
knife4j:
basic:
enable: true
password: 123456
username: admin
enable: true
production: false
setting:
enableFooter: false
enableFooterCustom: true
enableOpenApi: false
enableSwaggerModels: false
footerCustomContent: Apache License 2.0
mybatis-plus:
configuration:
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: ASSIGN_ID
logic-delete-field: DELETE_FLAG
logic-delete-value: DELETED
logic-not-delete-value: NOT_DELETE
enable-sql-runner: true
mapper-locations: classpath*:mjkf/xinke/**/mapping/*.xml,com/bstek/**/mapping/*.xml
type-handlers-package: mjkf.xinke.common.handler
sa-token:
activity-timeout: -1
alone-redis:
database: 2
host: ${spring.redis.host}
lettuce:
pool:
max-active: ${spring.redis.lettuce.pool.max-active}
max-idle: ${spring.redis.lettuce.pool.max-idle}
max-wait: ${spring.redis.lettuce.pool.max-wait}
min-idle: ${spring.redis.lettuce.pool.min-idle}
password: ${spring.redis.password}
port: ${spring.redis.port}
timeout: ${spring.redis.timeout}
is-concurrent: true
is-log: false
is-print: false
is-share: false
max-login-count: -1
timeout: 2592000
token-name: token
token-style: random-32
server:
port: 9882
mjkf-xinke:
config:
common:
backend-url: http://localhost:9882
front-url: http://localhost:9881
ten:
default-ten-id: -1
enabled: true
ignore-table-names: ''
ten-id-column-name: TENANT_ID
spring:
datasource:
druid:
stat-view-servlet:
enabled: true
login-password: 123456
login-username: admin
dynamic:
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
password: Xxs123456
url: jdbc:mysql://192.168.1.3:4306/material_manage?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&useInformationSchema=true
username: root
druid:
break-after-acquire-failure: false
filters: stat
initial-size: 5
max-active: 20
max-pool-prepared-statement-per-connection-size: 20
max-wait: 60000
min-evictable-idle-time-millis: 300000
min-idle: 5
pool-prepared-statements: true
test-on-borrow: false
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 6000
validation-query-timeout: 2000
public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMWiTVtdXFVrgFHDDKELZM0SywkWY3KjugN90eY5Sogon1j8Y0ClPF7nx3FuE7pAeBKiv7ChIS0vvx/59WUpKmUCAwEAAQ==
strict: true
jackson:
date-format: yyyy-MM-dd HH:mm:ss
locale: zh_CN
time-zone: GMT+8
profiles:
active: local
redis:
database: 1
host: 127.0.0.1
lettuce:
pool:
max-active: 200
max-idle: 10
max-wait: -1ms
min-idle: 0
password: ''
port: 6379
timeout: 10s
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB

View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--日志格式应用spring boot默认的格式也可以自己更改-->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!--定义日志存放的位置,默认存放在项目启动的相对路径的目录-->
<springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="app-log"/>
<!-- ****************************************************************************************** -->
<!-- ****************************** 本地开发只在控制台打印日志 ************************************ -->
<!-- ****************************************************************************************** -->
<springProfile name="local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--默认所有的包以info-->
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<!--各个服务的包在本地执行的时候打开debug模式-->
<logger name="mjkf.xinke" level="info" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
</springProfile>
<!-- ********************************************************************************************** -->
<!-- **** 放到服务器上不管在什么环境都只在文件记录日志控制台catalina.out打印logback捕获不到的日志 **** -->
<!-- ********************************************************************************************** -->
<springProfile name="!local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 日志记录器,日期滚动记录 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_error.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录error级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志记录器,日期滚动记录 -->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/log_total.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/total/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外还配置了日志文件不能超过2M若超过2M日志文件会以索引0开始
命名日志文件例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--记录到文件时记录两类一类是error日志一个是所有日志-->
<root level="info">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_ALL"/>
</root>
</springProfile>
</configuration>