feat: 提交课表冲突检查相关功能模块

This commit is contained in:
dengxiaoyue
2026-08-21 14:39:03 +08:00
parent 179b12e3bf
commit f190c29e05
857 changed files with 10838 additions and 5 deletions
@@ -0,0 +1,284 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.service.TimetableConflictService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.unit.conflict.TimetableConflictDimension;
import com.roomroot.jwgl.vo.timetableconflict.TimetableConflictCardVO;
import com.roomroot.jwgl.vo.timetableconflict.TimetableConflictDetailVO;
import com.roomroot.jwgl.vo.timetableconflict.TimetableConflictSummaryVO;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* 课表冲突检查控制器。
* <p>
* 【涉及数据库表总览】(每类冲突用到的具体表详见各方法内部注释):
* <pre>
* 核心表(必用):
* 实施_课程表 SSKCB —— 日期、节次、年度、删除状态、课程科目编号
* 实施_课程表_学员队 SSKCBXYD —— 课次与教学班次(学员队)的多对多关联
* 实施_课程表_辅助教员 SSKCBFZJY —— 课次与教员(主讲/辅讲)的多对多关联
* 实施_课程表_教室 SSKCBJS —— 课次与教室的多对多关联
* 翻译表(可选,用于中文名展示;即使不存在也不会阻断聚合结果):
* 学员队表 XYDB —— 班次中文名
* 教员表 / 教研室人员 JYB / JYSX —— 教员姓名
* 教室表 JSB —— 教室名称
* 课表 KB —— 课程名称、课程类型(必修/选修)
* </pre>
* </p>
*
* @author management
*/
@RestController
@RequestMapping("/timetable-conflict")
public class TimetableConflictController {
/**
* 课表冲突检查业务服务。
* 内部维护 ConcurrentHashMap 按「年度_维度编码」为 key 缓存每次检查结果明细,
* 避免重复执行 GROUP BY+HAVING COUNT 聚合 SQL。
*/
@Resource
private TimetableConflictService timetableConflictService;
// =====================================================================
// 接口 1:单维度冲突检查(原接口2,移除/summary后接口序号前移)
// =====================================================================
/**
* 执行指定维度的冲突检查。
* <p>
* 对应页面每张卡片右下角「检查」按钮。根据前端传入的 dimensionCode
* 分发到 Service → Mapper,执行对应的 GROUP BY + HAVING COUNT(DISTINCT) 聚合 SQL。
* 执行完成后:① 结果写入缓存 ② 可选写落库表 ③ 返回该卡片的最新状态。
* </p>
* <p>
* 不同 dimensionCode 用到的数据库表:
* <ul>
* <li>TEAM_CONFLICT(教学班时间冲突):
* 实施_课程表 SSKCB + 实施_课程表_学员队 SSKCBXYD + 学员队表 XYDB + 课表 KB</li>
* <li>ELECTIVE_REQUIRED_CONFLICT(必修选修冲突):
* 实施_课程表 SSKCB + 实施_课程表_学员队 SSKCBXYD + 学员队表 XYDB + 课表 KB(课程类型字段)</li>
* <li>TEACHER_CONFLICT(教员时间冲突):
* 实施_课程表 SSKCB + 实施_课程表_辅助教员 SSKCBFZJY + 教员表 JYB/教研室人员 + 课表 KB</li>
* <li>CLASSROOM_CONFLICT(教室时间冲突):
* 实施_课程表 SSKCB + 实施_课程表_教室 SSKCBJS + 教室表 JSB + 课表 KB</li>
* <li>GUARANTEE_CONFLICT(保障资源冲突,预留):
* 课程保障明细表 KCBBZMX + 保障类别 BZLB,当前返回空不报错</li>
* <li>EVENT_CONFLICT(活动事件冲突,预留):
* 学期校历 XQ + 学员队期班历 XYJXQJB,当前返回空不报错</li>
* </ul>
* </p>
*
* @param body 请求体 JSON,结构:
* {
* "nd": 2026, // 年度,必需
* "dimensionCode": "TEAM_CONFLICT", // 维度编码(见枚举 TimetableConflictDimension.code
* "writeToDb": false, // 【可选】是否同时写入"课表_冲突检查结果"表,默认 false
* "jcpch": null // 【可选】批次号(writeToDb=true 时,不传则自动生成一个)
* }
* @return 单卡片检查结果 VO
*/
@PostMapping("/check")
public Result<TimetableConflictCardVO> checkDimension(@RequestBody Map<String, Object> body) {
// 1. 提取并校验参数
Object ndObj = body.get("nd");
if (ndObj == null) {
return Result.badRequest("年度(nd)不能为空");
}
Integer nd = Integer.parseInt(String.valueOf(ndObj));
String code = (String) body.get("dimensionCode");
TimetableConflictDimension dim = TimetableConflictDimension.of(code);
if (dim == null) {
return Result.badRequest("无效的冲突检查维度编码:dimensionCode=" + code);
}
// 2. 新参数:是否落库 / 指定批次号
boolean writeToDb = Boolean.TRUE.equals(body.get("writeToDb"));
String jcpch = (String) body.get("jcpch");
// 3. 执行业务层单维度检查(内存 + 可选落库)
TimetableConflictCardVO card = timetableConflictService.checkDimension(nd, dim, jcpch, writeToDb);
// 4. 组装提示信息(落库模式下把批次号带给前端,便于后续 /details 用 useDb 查询)
String msg;
if (writeToDb) {
// 单维度 check:jcpch 传了就用传的,没传就是 service 内部生成的一个——这里拿不到内部生成的,
// 只能提示"已落库";如果批次号对前端重要,建议前端调 /check-all 统一拿批次号。
msg = "" + card.getTitle() + "】检查完成(已落库),发现 "
+ card.getConflictCount() + " 条冲突";
} else {
msg = "" + card.getTitle() + "】检查完成,发现 "
+ card.getConflictCount() + " 条冲突";
}
return Result.success(msg, card);
}
// =====================================================================
// 接口 2:执行全部维度检查
// =====================================================================
/**
* 执行所有维度的课表冲突检查。
* <p>
* 对应页面右上角「执行全部检查」按钮。内部依次对 6 个维度调用 {@link #checkDimension}
* 教学班 → 必修选修 → 教员 → 教室 → 保障资源(占位) → 活动事件(占位)
* 所有维度 SQL 执行完后汇总返回。fullyChecked 会被标记为 true。
* </p>
* <p>
* 方案 A 落库模式:当 writeToDb=true 时,内部自动生成一个统一批次号(jcpch,格式 {@code 年度_时间戳毫秒}),
* 6 个维度的所有冲突明细都会带上这个批次号一起写进【课表_冲突检查结果】表;
* 返回的 Result.message 会把本次批次号拼在提示文字里,前端可以保存并在后续
* {@code GET /details?useDb=true&jcpch=xxx} 中拉取该次检查的历史明细。
* </p>
*
* @param body 请求体 JSON,结构:
* {
* "nd": 2026, // 年度,必需
* "writeToDb": false // 【可选】true=同时写入"课表_冲突检查结果"表(生成统一批次号),默认 false
* }
* @return 完整汇总 VO6 张卡片 + 总冲突数 + fullyChecked=true)。
* 落库模式下 message 形如:"全维度检查完成(批次号:2026_20260821-153000-123),共发现 N 条冲突"
*/
@PostMapping("/check-all")
public Result<TimetableConflictSummaryVO> checkAll(@RequestBody Map<String, Object> body) {
Object ndObj = body.get("nd");
if (ndObj == null) {
return Result.badRequest("年度(nd)不能为空");
}
Integer nd = Integer.parseInt(String.valueOf(ndObj));
// 新参数:是否落库(=true 时 service 内部生成一个统一批次号,6 个维度共用)
boolean writeToDb = Boolean.TRUE.equals(body.get("writeToDb"));
TimetableConflictSummaryVO result = timetableConflictService.checkAll(nd, writeToDb);
// 组装返回 message,落库模式带上批次号(前端保存后可在 /details 用 useDb=true 查询)
String msg;
if (writeToDb) {
String batchNo = timetableConflictService.getLastBatchNo();
msg = "全维度检查完成(批次号:" + batchNo + "),共发现 "
+ result.getTotalConflictCount() + " 条冲突";
} else {
msg = "全维度检查完成,共发现 "
+ result.getTotalConflictCount() + " 条冲突";
}
return Result.success(msg, result);
}
// =====================================================================
// 接口 3:重置检查结果(清空缓存)
// =====================================================================
/**
* 重置当前学期的课表冲突检查结果。
* <p>
* 对应页面「重置」按钮。默认行为:
* 清除 Service 层 ConcurrentHashMap 中所有以 "{nd}_" 开头的 key 的缓存记录,
* 所有卡片恢复 checked=false / conflictCount=0 的初始状态。
* </p>
* <p>
* 可选行为(clearDb=true):同步 DELETE 【课表_冲突检查结果】表中该年度的全部批次记录,
* 用于"彻底清空历史检查痕迹"的场景(默认 false,保持历史,避免误删)。
* </p>
*
* @param body 请求体 JSON,结构:
* {
* "nd": 2026, // 年度,必需
* "clearDb": false // 【可选】true=同时清空落库表中该年度所有批次,默认 false
* }
* @return 重置后的汇总 VO(所有卡片均为未检查状态)
*/
@PostMapping("/reset")
public Result<TimetableConflictSummaryVO> reset(@RequestBody Map<String, Object> body) {
Object ndObj = body.get("nd");
if (ndObj == null) {
return Result.badRequest("年度(nd)不能为空");
}
Integer nd = Integer.parseInt(String.valueOf(ndObj));
// 新参数:是否同时清落库表(默认只清内存,保留历史)
boolean clearDb = Boolean.TRUE.equals(body.get("clearDb"));
TimetableConflictSummaryVO result = timetableConflictService.reset(nd, clearDb);
String msg = clearDb
? "检查结果已重置(已同步清空落库表中该年度的所有历史批次)"
: "检查结果已重置(仅清内存缓存,落库历史记录保留)";
return Result.success(msg, result);
}
// =====================================================================
// 接口 4:分页查询冲突明细
// =====================================================================
/**
* 分页查询冲突明细(页面下方"冲突明细"表格使用)。
* <p>
* <b>两种数据源(useDb 参数切换):</b>
* <ul>
* <li>useDb=false(默认,兼容旧前端):从 Service 内存缓存(ConcurrentHashMap)读。
* <b>必须先点击单卡片"检查"按钮或"执行全部检查"后,才能查到对应明细。</b>
* 若尚未检查 → 返回 records=[](前端显示"请先点击上方卡片「检查」按钮"的空状态)。</li>
* <li>useDb=true(方案 A 落库模式):从【课表_冲突检查结果】表读。
* 好处:JVM 重启不丢、可回看任意一次历史批次。
* 此时 jcpch 参数有意义:传具体批次号 → 只查那一次;不传 → 自动取该年度的最新批次。</li>
* </ul>
* </p>
*
* @param nd 年度(学期过滤),必需
* @param dimensionCode 维度编码(可选)。传 null / "ALL" 表示合并展示所有维度的冲突;
* 也可传单一维度编码(如 "TEACHER_CONFLICT")只看教员冲突。
* @param pageNum 当前页码(从 1 开始,默认 1)
* @param pageSize 每页大小(默认 20 条)
* @param useDb 【可选】true=从落库表查;false=从内存缓存查(默认)
* @param jcpch 【可选,useDb=true 时生效】查哪一个检查批次号。
* 不传则自动取该年度在 DB 中的"最新批次"MAX 创建时间)。
* @return 分页结果。每条明细包含:冲突号、课程、日期、节次、班次、教员、场地、责任单位
*/
@GetMapping("/details")
public Result<PageResult<TimetableConflictDetailVO>> getDetails(
@RequestParam(value = "nd") Integer nd,
@RequestParam(value = "dimensionCode", required = false) String dimensionCode,
@RequestParam(value = "pageNum", required = false) Integer pageNum,
@RequestParam(value = "pageSize", required = false) Integer pageSize,
@RequestParam(value = "useDb", required = false, defaultValue = "false") boolean useDb,
@RequestParam(value = "jcpch", required = false) String jcpch) {
PageResult<TimetableConflictDetailVO> page
= timetableConflictService.getDetailsPage(nd, dimensionCode, pageNum, pageSize, useDb, jcpch);
String msg = useDb
? "查询成功(数据源:落库表" + (jcpch != null && !jcpch.isEmpty() ? ",批次号=" + jcpch : ",最新批次") + ""
: "查询成功(数据源:内存缓存)";
return Result.success(msg, page);
}
// =====================================================================
// 接口 5:查询指定年度的检查批次号列表(落库模式辅助接口)
// =====================================================================
/**
* 查询指定年度的全部检查批次号(按创建时间倒序,最新排第一)。
* <p>
* 前端用途:"查看历史检查"下拉框,用户选择某次批次号后,
* 再调用 {@code GET /details?useDb=true&jcpch=xxx} 拉取那次的明细。
* </p>
*
* @param nd 年度,必需
* @return 批次号字符串列表(空表示无历史)
*/
@GetMapping("/batch-nos")
public Result<java.util.List<String>> listBatchNos(
@RequestParam(value = "nd") Integer nd) {
java.util.List<String> list = timetableConflictService.listBatchNos(nd);
return Result.success("查询成功,共 " + list.size() + " 个批次", list);
}
}
@@ -0,0 +1 @@
restart.include.json=/com.alibaba.fastjson2.*.jar
@@ -0,0 +1,56 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 达梦连接串:ip:端口,schema指定默认模式
url: jdbc:dm://10.1.1.17:5236?schema=JIAOWU&useUnicode=true&characterEncoding=utf-8
username: JIAOWU
password: Jiaowu123
driver-class-name: dm.jdbc.driver.DmDriver
# Druid 基础参数
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: roomroot
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
db-type: dm
@@ -0,0 +1,149 @@
# 项目相关配置
roomroot:
# 名称
name: roomroot
# 版本
version: 3.9.2
# 版权年份
copyrightYear: 2026
# 文件路径 示例( Windows配置D:/roomroot/uploadPathLinux配置 /home/roomroot/uploadPath
profile: D:/roomroot/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /api
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 1000
threads:
# tomcat最大线程数,默认为200
max: 800
# Tomcat启动初始化的线程数,默认值10
min-spare: 100
# 日志配置
logging:
level:
com.roomroot: debug
#org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
data:
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 30
# MyBatis-Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.roomroot.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:com/roomroot/**/mapper/*.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# Springdoc配置
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui.html
tags-sorter: alpha
group-configs:
- group: 'default'
display-name: '测试模块'
paths-to-match: '/**'
packages-to-scan: com.roomroot.web.controller.tool
# 防盗链配置
referer:
# 防盗链开关
enabled: false
# 允许的域名列表
allowed-domains: localhost,127.0.0.1,roomroot.vip,www.roomroot.vip
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 自定义内嵌Redis开关
custom:
embedded-redis:
# dev环境true自动启动内嵌Redisprod改为false使用外部Redis
enable: false
port: 6379
max-memory: 128M
@@ -0,0 +1,5 @@
Application Version: ${roomroot.version}
Spring Boot Version: ${spring-boot.version}
////////////////////////////////////////////////////////////////////
// 启动开始 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////
@@ -0,0 +1,38 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
login.blocked=很遗憾,访问IP已被列入系统黑名单
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/roomroot/logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.roomroot" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局参数 -->
<settings>
<!-- 使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 允许JDBC 支持自动生成主键 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="SLF4J" />
<!-- 使用驼峰命名法转换字段 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
</settings>
</configuration>