mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-13 18:45:06 +08:00
项目结构调整 x 14 : 将 yudao-spring-boot-starter-mybatis 拆分
This commit is contained in:
@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.framework.datasource.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.datasource.core.filter.DruidAdRemoveFilter;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
* 数据库配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理
|
||||
@EnableConfigurationProperties(DruidStatProperties.class)
|
||||
public class YudaoDataSourceAutoConfiguration {
|
||||
|
||||
/**
|
||||
* 创建 DruidAdRemoveFilter 过滤器,过滤 common.js 的广告
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
|
||||
public FilterRegistrationBean<DruidAdRemoveFilter> druidAdRemoveFilterFilter(DruidStatProperties properties) {
|
||||
// 获取 druid web 监控页面的参数
|
||||
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
|
||||
// 提取 common.js 的配置路径
|
||||
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
|
||||
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
|
||||
// 创建 DruidAdRemoveFilter Bean
|
||||
FilterRegistrationBean<DruidAdRemoveFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(new DruidAdRemoveFilter());
|
||||
registrationBean.addUrlPatterns(commonJsPattern);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.framework.datasource.core.enums;
|
||||
|
||||
/**
|
||||
* 对应于多数据源中不同数据源配置
|
||||
*
|
||||
* 通过在方法上,使用 {@link com.baomidou.dynamic.datasource.annotation.DS} 注解,设置使用的数据源。
|
||||
* 注意,默认是 {@link #MASTER} 数据源
|
||||
*
|
||||
* 对应官方文档为 http://dynamic-datasource.com/guide/customize/Annotation.html
|
||||
*/
|
||||
public interface DataSourceEnum {
|
||||
|
||||
/**
|
||||
* 主库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Master} 注解
|
||||
*/
|
||||
String MASTER = "master";
|
||||
/**
|
||||
* 从库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Slave} 注解
|
||||
*/
|
||||
String SLAVE = "slave";
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.framework.datasource.core.filter;
|
||||
|
||||
import com.alibaba.druid.util.Utils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Druid 底部广告过滤器
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class DruidAdRemoveFilter extends OncePerRequestFilter {
|
||||
|
||||
/**
|
||||
* common.js 的路径
|
||||
*/
|
||||
private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
chain.doFilter(request, response);
|
||||
// 重置缓冲区,响应头不会被重置
|
||||
response.resetBuffer();
|
||||
// 获取 common.js
|
||||
String text = Utils.readFromResource(COMMON_JS_ILE_PATH);
|
||||
// 正则替换 banner, 除去底部的广告信息
|
||||
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
|
||||
text = text.replaceAll("powered.*?shrek.wang</a>", "");
|
||||
response.getWriter().write(text);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 数据库连接池,采用 Druid
|
||||
* 多数据源,采用爆米花
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.datasource;
|
@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* MyBaits 配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class,
|
||||
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
|
||||
public class YudaoMybatisAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
|
||||
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
|
||||
return mybatisPlusInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetaObjectHandler defaultMetaObjectHandler(){
|
||||
return new DefaultDBFieldHandler(); // 自动填充参数类
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 基础实体对象
|
||||
*/
|
||||
@Data
|
||||
public class BaseDO implements Serializable {
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String creator;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updater;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 通用参数填充实现类
|
||||
*
|
||||
* 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值
|
||||
*
|
||||
* @author hexiaowu
|
||||
*/
|
||||
public class DefaultDBFieldHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
||||
Date current = new Date();
|
||||
|
||||
// 创建时间为空,则以当前时间为插入时间
|
||||
if (Objects.isNull(baseDO.getCreateTime())) {
|
||||
baseDO.setCreateTime(current);
|
||||
}
|
||||
// 更新时间为空,则以当前时间为更新时间
|
||||
if (Objects.isNull(baseDO.getUpdateTime())) {
|
||||
baseDO.setUpdateTime(current);
|
||||
}
|
||||
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getCreator())) {
|
||||
baseDO.setCreator(loginUser.getId().toString());
|
||||
}
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(loginUser.getId().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
Object modifyTime = getFieldValByName("updateTime", metaObject);
|
||||
Object modifier = getFieldValByName("updater", metaObject);
|
||||
// 获取登录用户信息
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
|
||||
// 更新时间为空,则以当前时间为更新时间
|
||||
if (Objects.isNull(modifyTime)) {
|
||||
setFieldValByName("updateTime", new Date(), metaObject);
|
||||
}
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
if (Objects.nonNull(loginUser) && Objects.isNull(modifier)) {
|
||||
setFieldValByName("updater", loginUser.getId().toString(), metaObject);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.mapper;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
|
||||
*/
|
||||
public interface BaseMapperX<T> extends BaseMapper<T> {
|
||||
|
||||
default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
|
||||
// MyBatis Plus 查询
|
||||
IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
|
||||
selectPage(mpPage, queryWrapper);
|
||||
// 转换返回
|
||||
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
|
||||
}
|
||||
|
||||
default T selectOne(String field, Object value) {
|
||||
return selectOne(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
default Integer selectCount(String field, Object value) {
|
||||
return selectCount(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
default List<T> selectList() {
|
||||
return selectList(new QueryWrapper<>());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
|
||||
*
|
||||
* 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。
|
||||
*
|
||||
* @param <T> 数据类型
|
||||
*/
|
||||
public class QueryWrapperX<T> extends QueryWrapper<T> {
|
||||
|
||||
public QueryWrapperX<T> likeIfPresent(String column, String val) {
|
||||
if (StringUtils.hasText(val)) {
|
||||
return (QueryWrapperX<T>) super.like(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> inIfPresent(String column, Collection<?> values) {
|
||||
if (!CollectionUtils.isEmpty(values)) {
|
||||
return (QueryWrapperX<T>) super.in(column, values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> inIfPresent(String column, Object... values) {
|
||||
if (!ArrayUtils.isEmpty(values)) {
|
||||
return (QueryWrapperX<T>) super.in(column, values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> eqIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.eq(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> neIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.ne(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> gtIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.gt(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> geIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.ge(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> ltIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.lt(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> leIfPresent(String column, Object val) {
|
||||
if (val != null) {
|
||||
return (QueryWrapperX<T>) super.le(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapperX<T> betweenIfPresent(String column, Object val1, Object val2) {
|
||||
if (val1 != null && val2 != null) {
|
||||
return (QueryWrapperX<T>) super.between(column, val1, val2);
|
||||
}
|
||||
if (val1 != null) {
|
||||
return (QueryWrapperX<T>) ge(column, val1);
|
||||
}
|
||||
if (val2 != null) {
|
||||
return (QueryWrapperX<T>) le(column, val2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// ========== 重写父类方法,方便链式调用 ==========
|
||||
|
||||
@Override
|
||||
public QueryWrapperX<T> eq(boolean condition, String column, Object val) {
|
||||
super.eq(condition, column, val);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryWrapperX<T> eq(String column, Object val) {
|
||||
super.eq(column, val);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryWrapperX<T> orderByDesc(String column) {
|
||||
super.orderByDesc(true, column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryWrapperX<T> last(String lastSql) {
|
||||
super.last(lastSql);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryWrapperX<T> in(String column, Collection<?> coll) {
|
||||
super.in(column, coll);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.type;
|
||||
|
||||
import cn.iocoder.yudao.framework.util.json.JsonUtils;
|
||||
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 参考 {@link com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler} 实现
|
||||
* 在我们将字符串反序列化为 Set 并且泛型为 Long 时,如果每个元素的数值太小,会被处理成 Integer 类型,导致可能存在隐性的 BUG。
|
||||
*
|
||||
* 例如说哦,SysUserDO 的 postIds 属性
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class JsonLongSetTypeHandler extends AbstractJsonTypeHandler<Object> {
|
||||
|
||||
private static final TypeReference<Set<Long>> typeReference = new TypeReference<Set<Long>>(){};
|
||||
|
||||
@Override
|
||||
protected Object parse(String json) {
|
||||
return JsonUtils.parseObject(json, typeReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJson(Object obj) {
|
||||
return JsonUtils.toJsonString(obj);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.SortingField;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* MyBatis 工具类
|
||||
*/
|
||||
public class MyBatisUtils {
|
||||
|
||||
public static <T> Page<T> buildPage(PageParam pageParam) {
|
||||
return buildPage(pageParam, null);
|
||||
}
|
||||
|
||||
public static <T> Page<T> buildPage(PageParam pageParam, Collection<SortingField> sortingFields) {
|
||||
// 页码 + 数量
|
||||
Page<T> page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
|
||||
// 排序字段
|
||||
if (!CollectionUtil.isEmpty(sortingFields)) {
|
||||
page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ?
|
||||
OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 使用 MyBatis Plus 提升使用 MyBatis 的开发效率
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.mybatis;
|
@ -0,0 +1 @@
|
||||
package cn.iocoder.yudao.framework;
|
@ -0,0 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration,\
|
||||
cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration
|
Reference in New Issue
Block a user