Commit 6472d7ed authored by 雍欢's avatar 雍欢

1. 可以关闭系统日志;

2. 可异步写系统日志;
3. 修复:MySQL数据库下面数据导出出错
parent 0f84de0c
package com.huigou.data.excel.exporter; package com.huigou.data.excel.exporter;
import java.awt.Color; import com.huigou.cache.DictUtil;
import java.io.File; import com.huigou.cache.SystemCache;
import java.io.FileInputStream; import com.huigou.data.exception.ExportExcelException;
import java.io.FileOutputStream; import com.huigou.data.jdbc.JDBCDao;
import java.io.IOException; import com.huigou.data.jdbc.QueryRowMapper;
import java.io.InputStream; import com.huigou.util.*;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
...@@ -35,20 +18,20 @@ import org.apache.poi.xssf.usermodel.XSSFSheet; ...@@ -35,20 +18,20 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dom4j.Element; import org.dom4j.Element;
import com.huigou.cache.DictUtil; import java.awt.*;
import com.huigou.cache.SystemCache; import java.io.*;
import com.huigou.data.exception.ExportExcelException; import java.sql.Clob;
import com.huigou.data.jdbc.JDBCDao; import java.sql.ResultSet;
import com.huigou.data.jdbc.QueryRowMapper; import java.sql.SQLException;
import com.huigou.util.ClassHelper; import java.util.List;
import com.huigou.util.Constants; import java.util.*;
import com.huigou.util.DateUtil; import java.util.zip.ZipEntry;
import com.huigou.util.FileHelper; import java.util.zip.ZipFile;
import com.huigou.util.StringUtil; import java.util.zip.ZipOutputStream;
/** /**
* excel2007是使用xml格式来存储这里通过生成xml字符串创建xlsx * excel2007是使用xml格式来存储这里通过生成xml字符串创建xlsx
* *
* @author xx * @author xx
*/ */
public class XSSFExport implements IExcelExport { public class XSSFExport implements IExcelExport {
...@@ -71,7 +54,9 @@ public class XSSFExport implements IExcelExport { ...@@ -71,7 +54,9 @@ public class XSSFExport implements IExcelExport {
public static interface XSWriteDelegate { public static interface XSWriteDelegate {
void onBeforeMergeCell(List<CellRangeAddress> rangeAddress); void onBeforeMergeCell(List<CellRangeAddress> rangeAddress);
}; }
;
private XSWriteDelegate delegate; private XSWriteDelegate delegate;
...@@ -116,10 +101,10 @@ public class XSSFExport implements IExcelExport { ...@@ -116,10 +101,10 @@ public class XSSFExport implements IExcelExport {
/** /**
* 添加表头 * 添加表头
* *
* @author
* @param c * @param c
* @throws * @throws
* @author
*/ */
private void addHeadCell(Cell c, String fieldCode) { private void addHeadCell(Cell c, String fieldCode) {
String key = c.getRowIndex() + "," + c.getColumnIndex(); String key = c.getRowIndex() + "," + c.getColumnIndex();
...@@ -128,10 +113,10 @@ public class XSSFExport implements IExcelExport { ...@@ -128,10 +113,10 @@ public class XSSFExport implements IExcelExport {
/** /**
* 根据行号获取表头 * 根据行号获取表头
* *
* @author
* @param rownum * @param rownum
* @throws * @throws
* @author
*/ */
private List<HeadCell> getHeadCells(int rownum) { private List<HeadCell> getHeadCells(int rownum) {
List<HeadCell> heads = new ArrayList<HeadCell>(fields.size()); List<HeadCell> heads = new ArrayList<HeadCell>(fields.size());
...@@ -180,11 +165,11 @@ public class XSSFExport implements IExcelExport { ...@@ -180,11 +165,11 @@ public class XSSFExport implements IExcelExport {
/** /**
* 创建Excel样式 * 创建Excel样式
* *
* @author
* @param wb * @param wb
* @return * @return
* @throws * @throws
* @author
*/ */
public void createStyles(XSSFWorkbook wb) { public void createStyles(XSSFWorkbook wb) {
Map<String, XSSFCellStyle> tmpStylesMap = new HashMap<String, XSSFCellStyle>(); Map<String, XSSFCellStyle> tmpStylesMap = new HashMap<String, XSSFCellStyle>();
...@@ -219,7 +204,7 @@ public class XSSFExport implements IExcelExport { ...@@ -219,7 +204,7 @@ public class XSSFExport implements IExcelExport {
/** /**
* 创建样式 * 创建样式
* *
* @param wb * @param wb
* @param type * @param type
* @return * @return
...@@ -258,7 +243,7 @@ public class XSSFExport implements IExcelExport { ...@@ -258,7 +243,7 @@ public class XSSFExport implements IExcelExport {
/** /**
* 解析颜色字符串 * 解析颜色字符串
* *
* @param colorString * @param colorString
* @return * @return
*/ */
...@@ -273,7 +258,7 @@ public class XSSFExport implements IExcelExport { ...@@ -273,7 +258,7 @@ public class XSSFExport implements IExcelExport {
/** /**
* 根据编码取样式 * 根据编码取样式
* *
* @param type * @param type
* @return * @return
*/ */
...@@ -290,11 +275,11 @@ public class XSSFExport implements IExcelExport { ...@@ -290,11 +275,11 @@ public class XSSFExport implements IExcelExport {
/** /**
* 解析表头 * 解析表头
* *
* @author
* @param sheet * @param sheet
* @return * @return
* @throws * @throws
* @author
*/ */
public int createHead(Sheet sheet) { public int createHead(Sheet sheet) {
Object[] tables_obj = headRoot.elements().toArray(); Object[] tables_obj = headRoot.elements().toArray();
...@@ -408,13 +393,13 @@ public class XSSFExport implements IExcelExport { ...@@ -408,13 +393,13 @@ public class XSSFExport implements IExcelExport {
/** /**
* 写入数据 * 写入数据
* *
* @author
* @param out * @param out
* @param stylesMap * @param stylesMap
* @param index * @param index
* @throws Exception * @throws Exception
* @throws * @throws
* @author
*/ */
private void generate(Writer out, int index) throws Exception { private void generate(Writer out, int index) throws Exception {
SpreadsheetWriter sw = new SpreadsheetWriter(out); SpreadsheetWriter sw = new SpreadsheetWriter(out);
...@@ -456,13 +441,12 @@ public class XSSFExport implements IExcelExport { ...@@ -456,13 +441,12 @@ public class XSSFExport implements IExcelExport {
} }
/** /**
* @throws SQLException
* 循环写入数据
* @author
* @param sw * @param sw
* @param stylesMap * @param stylesMap
* @param index * @param index
* @throws SQLException 循环写入数据
* @throws * @throws
* @author
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void writeDatas(SpreadsheetWriter sw, int index) throws IOException, SQLException { private void writeDatas(SpreadsheetWriter sw, int index) throws IOException, SQLException {
...@@ -499,15 +483,14 @@ public class XSSFExport implements IExcelExport { ...@@ -499,15 +483,14 @@ public class XSSFExport implements IExcelExport {
} }
/** /**
* @throws SQLException
* 写单元格
* @author
* @param sw * @param sw
* @param index * @param index
* @param exportField * @param exportField
* @param value * @param value
* @param stylesMap * @param stylesMap
* @throws SQLException 写单元格
* @throws * @throws
* @author
*/ */
private void writeDataCell(SpreadsheetWriter sw, int index, String fieldType, XSSFCellStyle style, Object value) throws IOException, SQLException { private void writeDataCell(SpreadsheetWriter sw, int index, String fieldType, XSSFCellStyle style, Object value) throws IOException, SQLException {
String valueStr = ""; String valueStr = "";
...@@ -550,18 +533,18 @@ public class XSSFExport implements IExcelExport { ...@@ -550,18 +533,18 @@ public class XSSFExport implements IExcelExport {
} else if (value instanceof java.math.BigDecimal) { } else if (value instanceof java.math.BigDecimal) {
sw.createCell(index, value.toString(), style.getIndex()); sw.createCell(index, value.toString(), style.getIndex());
} else { } else {
sw.createCell(index, (String) value, style.getIndex()); sw.createCell(index, value != null ? String.valueOf(value) : "", style.getIndex());
} }
} }
/** /**
* 写入合计信息 * 写入合计信息
* *
* @author
* @param sw * @param sw
* @param rownum * @param rownum
* @param stylesMap * @param stylesMap
* @throws * @throws
* @author
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void writeTotalField(SpreadsheetWriter sw, int rownum) throws IOException { private void writeTotalField(SpreadsheetWriter sw, int rownum) throws IOException {
...@@ -590,12 +573,12 @@ public class XSSFExport implements IExcelExport { ...@@ -590,12 +573,12 @@ public class XSSFExport implements IExcelExport {
/** /**
* 执行查询并导出 * 执行查询并导出
* *
* @author
* @param queryModel * @param queryModel
* @return * @return
* @throws Exception * @throws Exception
* @throws * @throws
* @author
*/ */
public String expExcel(String sql, Map<String, Object> param, JDBCDao jdbcDao) throws Exception { public String expExcel(String sql, Map<String, Object> param, JDBCDao jdbcDao) throws Exception {
// 创建临时文件 用于生成样式及表头 // 创建临时文件 用于生成样式及表头
...@@ -629,13 +612,13 @@ public class XSSFExport implements IExcelExport { ...@@ -629,13 +612,13 @@ public class XSSFExport implements IExcelExport {
/** /**
* 执行查询并写入数据 * 执行查询并写入数据
* *
* @author
* @param out * @param out
* @param stylesMap * @param stylesMap
* @param index * @param index
* @throws Exception * @throws Exception
* @throws * @throws
* @author
*/ */
public void generate(Writer out, final int index, String sql, Map<String, Object> param, JDBCDao jdbcDao) throws Exception { public void generate(Writer out, final int index, String sql, Map<String, Object> param, JDBCDao jdbcDao) throws Exception {
final SpreadsheetWriter sw = new SpreadsheetWriter(out); final SpreadsheetWriter sw = new SpreadsheetWriter(out);
...@@ -685,12 +668,12 @@ public class XSSFExport implements IExcelExport { ...@@ -685,12 +668,12 @@ public class XSSFExport implements IExcelExport {
/** /**
* 从rs中读取需要的数据 * 从rs中读取需要的数据
* *
* @author
* @param field * @param field
* @param rs * @param rs
* @return * @return
* @throws * @throws
* @author
*/ */
public Object getObjectValue(ExportField field, ResultSet rs) throws SQLException { public Object getObjectValue(ExportField field, ResultSet rs) throws SQLException {
String fieldName = field.getField(); String fieldName = field.getField();
...@@ -721,15 +704,11 @@ public class XSSFExport implements IExcelExport { ...@@ -721,15 +704,11 @@ public class XSSFExport implements IExcelExport {
} }
/** /**
* @param zipfile * @param zipfile the template file
* the template file * @param tmpfile the XML file with the sheet data
* @param tmpfile * @param entry the name of the sheet entry to substitute, e.g.
* the XML file with the sheet data * xl/worksheets/sheet1.xml
* @param entry * @param out the stream to write the result to
* the name of the sheet entry to substitute, e.g.
* xl/worksheets/sheet1.xml
* @param out
* the stream to write the result to
*/ */
private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException { private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
ZipFile zip = new ZipFile(zipfile); ZipFile zip = new ZipFile(zipfile);
...@@ -831,7 +810,7 @@ public class XSSFExport implements IExcelExport { ...@@ -831,7 +810,7 @@ public class XSSFExport implements IExcelExport {
/** /**
* 处理xml中无法识别的字符 * 处理xml中无法识别的字符
* *
* @param data * @param data
* @return * @return
*/ */
...@@ -842,7 +821,7 @@ public class XSSFExport implements IExcelExport { ...@@ -842,7 +821,7 @@ public class XSSFExport implements IExcelExport {
for (int i = 0; i < data.length(); i++) { for (int i = 0; i < data.length(); i++) {
char ch = data.charAt(i); char ch = data.charAt(i);
if ((ch == 0x9) || (ch == 0xA) || (ch == 0xD) || ((ch >= 0x20) && (ch <= 0xD7FF)) || ((ch >= 0xE000) && (ch <= 0xFFFD)) if ((ch == 0x9) || (ch == 0xA) || (ch == 0xD) || ((ch >= 0x20) && (ch <= 0xD7FF)) || ((ch >= 0xE000) && (ch <= 0xFFFD))
|| ((ch >= 0x10000) && (ch <= 0x10FFFF))) { || ((ch >= 0x10000) && (ch <= 0x10FFFF))) {
appender.append(ch); appender.append(ch);
} }
} }
...@@ -870,11 +849,11 @@ public class XSSFExport implements IExcelExport { ...@@ -870,11 +849,11 @@ public class XSSFExport implements IExcelExport {
/** /**
* 通过列索引获取Excel其对应列的字母 * 通过列索引获取Excel其对应列的字母
* *
* @author
* @param num * @param num
* @return * @return
* @throws * @throws
* @author
*/ */
public static String getExcelName(int num) { public static String getExcelName(int num) {
StringBuffer temp = new StringBuffer(); StringBuffer temp = new StringBuffer();
......
package com.huigou.uasp.log.application.impl; package com.huigou.uasp.log.application.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;
import com.huigou.context.MessageSourceContext; import com.huigou.context.MessageSourceContext;
import com.huigou.context.TmspmConifg; import com.huigou.context.TmspmConifg;
import com.huigou.data.domain.model.MessageConstants; import com.huigou.data.domain.model.MessageConstants;
...@@ -25,6 +18,14 @@ import com.huigou.uasp.log.repository.DBBizLogRepository; ...@@ -25,6 +18,14 @@ import com.huigou.uasp.log.repository.DBBizLogRepository;
import com.huigou.util.ClassHelper; import com.huigou.util.ClassHelper;
import com.huigou.util.StringPool; import com.huigou.util.StringPool;
import com.huigou.util.StringUtil; import com.huigou.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
/** /**
* 日志应用 * 日志应用
...@@ -49,6 +50,7 @@ public class DBLogApplicationImpl implements LogApplication { ...@@ -49,6 +50,7 @@ public class DBLogApplicationImpl implements LogApplication {
@Autowired @Autowired
private TmspmConifg tmspmConifg; private TmspmConifg tmspmConifg;
@Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRES_NEW)
@Override @Override
public void savelog(BizLog bizLog, BizLogDetail bizLogDetail) { public void savelog(BizLog bizLog, BizLogDetail bizLogDetail) {
Assert.notNull(bizLog, "参数bizlog不能为空。"); Assert.notNull(bizLog, "参数bizlog不能为空。");
......
package com.huigou.uasp.log.aspect; package com.huigou.uasp.log.aspect;
import java.io.PrintWriter; import com.huigou.cache.SystemCache;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.huigou.context.ContextUtil; import com.huigou.context.ContextUtil;
import com.huigou.context.ThreadLocalUtil; import com.huigou.context.ThreadLocalUtil;
import com.huigou.context.TmspmConifg; import com.huigou.context.TmspmConifg;
...@@ -29,14 +16,36 @@ import com.huigou.uasp.log.domain.model.LogStatus; ...@@ -29,14 +16,36 @@ import com.huigou.uasp.log.domain.model.LogStatus;
import com.huigou.uasp.log.util.BizLogUtil; import com.huigou.uasp.log.util.BizLogUtil;
import com.huigou.util.Constants; import com.huigou.util.Constants;
import com.huigou.util.SDO; import com.huigou.util.SDO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.task.TaskExecutor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;
/** /**
* 日志切面 * 日志切面
* *
* @author gongmm * @author gongmm
*/ */
@Aspect @Aspect
public class LogAspect implements ApplicationContextAware { public class LogAspect implements ApplicationContextAware {
/**
* 系统参数:是否开启日志功能
*/
private final static String PARAMETER_LOGGING_ENABLED = "logging.enabled";
/**
* 系统参数:是否异步写日志
*/
private final static String PARAMETER_LOGGING_ASYNC = "logging.async";
@Autowired @Autowired
private ApplicationSystemApplication applicationSystemApplication; private ApplicationSystemApplication applicationSystemApplication;
...@@ -48,6 +57,7 @@ public class LogAspect implements ApplicationContextAware { ...@@ -48,6 +57,7 @@ public class LogAspect implements ApplicationContextAware {
private TmspmConifg tmspmConifg; private TmspmConifg tmspmConifg;
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private TaskExecutor asyncWriteExecutor;
/** /**
* 日志接口 * 日志接口
...@@ -58,6 +68,10 @@ public class LogAspect implements ApplicationContextAware { ...@@ -58,6 +68,10 @@ public class LogAspect implements ApplicationContextAware {
this.logApplication = logApplication; this.logApplication = logApplication;
} }
public void setAsyncWriteExecutor(TaskExecutor asyncWriteExecutor) {
this.asyncWriteExecutor = asyncWriteExecutor;
}
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
...@@ -80,13 +94,13 @@ public class LogAspect implements ApplicationContextAware { ...@@ -80,13 +94,13 @@ public class LogAspect implements ApplicationContextAware {
private void postMethodInvoke(BizLog bizLog, Throwable failureCause) { private void postMethodInvoke(BizLog bizLog, Throwable failureCause) {
bizLog.setEndDate(new Date()); bizLog.setEndDate(new Date());
SDO sdo = ThreadLocalUtil.getVariable(Constants.SDO, SDO.class); SDO sdo = ThreadLocalUtil.getVariable(Constants.SDO, SDO.class);
if (sdo != null) { if (sdo != null) {
String params = sdo.getProperties().toString(); String params = sdo.getProperties().toString();
bizLog.getBizLogDetail().setParams(params); bizLog.getBizLogDetail().setParams(params);
} }
Object exceptionMessage = BizLogUtil.getBizLogException(); Object exceptionMessage = BizLogUtil.getBizLogException();
if (failureCause != null || exceptionMessage != null) { if (failureCause != null || exceptionMessage != null) {
bizLog.setStatusId(LogStatus.FAILURE.getId()); bizLog.setStatusId(LogStatus.FAILURE.getId());
...@@ -106,7 +120,12 @@ public class LogAspect implements ApplicationContextAware { ...@@ -106,7 +120,12 @@ public class LogAspect implements ApplicationContextAware {
@Around("@annotation(com.huigou.uasp.log.annotation.LogInfo)") @Around("@annotation(com.huigou.uasp.log.annotation.LogInfo)")
public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null; Boolean enabled = SystemCache.getParameter(PARAMETER_LOGGING_ENABLED, Boolean.class);
if (Boolean.FALSE.equals(enabled)) {
// 没有开启日志功能
return proceedingJoinPoint.proceed();
}
Object result;
BizLog bizLog = preMethodInvoke(proceedingJoinPoint); BizLog bizLog = preMethodInvoke(proceedingJoinPoint);
Throwable failureCause = null; Throwable failureCause = null;
try { try {
...@@ -118,14 +137,20 @@ public class LogAspect implements ApplicationContextAware { ...@@ -118,14 +137,20 @@ public class LogAspect implements ApplicationContextAware {
failureCause = ex; failureCause = ex;
throw ex; throw ex;
} finally { } finally {
postMethodInvoke(bizLog, failureCause); Boolean async = SystemCache.getParameter(PARAMETER_LOGGING_ASYNC, Boolean.class);
if (Boolean.TRUE.equals(async) && asyncWriteExecutor != null) {
Throwable throwable = failureCause;
asyncWriteExecutor.execute(() -> postMethodInvoke(bizLog, throwable));
} else {
postMethodInvoke(bizLog, failureCause);
}
} }
return result; return result;
} }
/** /**
* 创建bizLog实例 * 创建bizLog实例
* *
* @return * @return
*/ */
private BizLog createBizLog() { private BizLog createBizLog() {
...@@ -134,7 +159,7 @@ public class LogAspect implements ApplicationContextAware { ...@@ -134,7 +159,7 @@ public class LogAspect implements ApplicationContextAware {
/** /**
* 创建bizLogDetail实例 * 创建bizLogDetail实例
* *
* @return * @return
*/ */
private BizLogDetail createBizLogDetail() { private BizLogDetail createBizLogDetail() {
...@@ -143,7 +168,7 @@ public class LogAspect implements ApplicationContextAware { ...@@ -143,7 +168,7 @@ public class LogAspect implements ApplicationContextAware {
/** /**
* 获取异常堆栈信息 * 获取异常堆栈信息
* *
* @param throwable * @param throwable
* @return * @return
*/ */
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation=" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 日志配置 --> <!-- 日志配置 -->
<!-- <!--
<bean id="logApplication" class="com.huigou.uasp.log.application.impl.MongoDBLogApplicationImpl"></bean> <bean id="logApplication" class="com.huigou.uasp.log.application.impl.MongoDBLogApplicationImpl"></bean>
<bean id="bizLogDetail" class="com.huigou.uasp.log.domain.model.MongoDBBizLogDetail" scope="prototype"></bean> <bean id="bizLogDetail" class="com.huigou.uasp.log.domain.model.MongoDBBizLogDetail" scope="prototype"></bean>
<bean id="bizLog" class="com.huigou.uasp.log.domain.model.MongoDBBizLog" scope="prototype"></bean> <bean id="bizLog" class="com.huigou.uasp.log.domain.model.MongoDBBizLog" scope="prototype"></bean>
<bean id="logAspect" class="com.huigou.uasp.log.aspect.LogAspect"> <bean id="logAspect" class="com.huigou.uasp.log.aspect.LogAspect">
<property name="logApplication" ref="logApplication"></property> <property name="logApplication" ref="logApplication"></property>
</bean> </bean>
--> -->
<bean id="logApplication" class="com.huigou.uasp.log.application.impl.DBLogApplicationImpl"></bean> <bean id="logApplication" class="com.huigou.uasp.log.application.impl.DBLogApplicationImpl"></bean>
<bean id="bizLogDetail" class="com.huigou.uasp.log.domain.model.DBBizLogDetail" scope="prototype"></bean> <bean id="bizLogDetail" class="com.huigou.uasp.log.domain.model.DBBizLogDetail" scope="prototype"></bean>
<bean id="bizLog" class="com.huigou.uasp.log.domain.model.DBBizLog" scope="prototype"></bean> <bean id="bizLog" class="com.huigou.uasp.log.domain.model.DBBizLog" scope="prototype"></bean>
<bean id="logAspect" class="com.huigou.uasp.log.aspect.LogAspect"> <bean id="logAspect" class="com.huigou.uasp.log.aspect.LogAspect">
<property name="logApplication" ref="logApplication"></property> <property name="logApplication" ref="logApplication"/>
<property name="asyncWriteExecutor">
<bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10"/>
<property name="maxPoolSize" value="20"/>
<property name="queueCapacity" value="200"/>
</bean>
</property>
</bean> </bean>
</beans> </beans>
\ No newline at end of file
/.settings
/.idea
/target
.classpath
.project
.tern-project
*.iml
/bin
/lib
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.huigou</groupId>
<artifactId>root</artifactId>
<version>1.2.2</version>
</parent>
<groupId>com.topsunit</groupId>
<artifactId>query-spring</artifactId>
<dependencies>
<dependency>
<groupId>com.huigou</groupId>
<artifactId>huigou-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.huigou</groupId>
<artifactId>huigou-data</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>topsunit</id>
<name>topsunit</name>
<url>http://nexus.local.topsunit.com/repository/huigou-repostitory/</url>
</repository>
</distributionManagement>
</project>
\ No newline at end of file
package com.topsunit.query;
import com.huigou.data.query.model.QueryDescriptor;
/**
* @author yonghuan
*/
public interface QueryDescriptorHolder {
/**
* 获取自定义查询的QueryDescriptor。
*
* @return 自定义查询的QueryDescriptor。
*/
QueryDescriptor getQueryDescriptor(String queryName);
}
package com.topsunit.query.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author yonghuan
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface Dictionaries {
Dictionary[] value();
}
package com.topsunit.query.annotations;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author yonghuan
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Repeatable(Dictionaries.class)
public @interface Dictionary {
/**
* 字典名字。
*/
String value();
/**
* 字段名。
*/
String field() default "";
}
package com.topsunit.query.annotations;
import java.lang.annotation.*;
/**
* @author yonghuan
* @see com.topsunit.query.QueryDescriptorHolder
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Mapper {
/**
* 自定义查询SQL文件
*
* @return 自定义查询SQL文件
*/
String xml() default "";
/**
* spring bean name
*
* @return spring bean name
* @since 1.1.3
*/
String value() default "";
}
package com.topsunit.query.annotations;
import java.lang.annotation.*;
/**
* @author yonghuan
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
/**
* 查询参数名。
*
* @return 查询参数名
*/
String value();
}
package com.topsunit.query.annotations;
import java.lang.annotation.*;
/**
* SQL 查询结果映射的Java类。
*
* @author yonghuan
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResultType {
Class<?> value();
}
package com.topsunit.query.annotations;
import java.lang.annotation.*;
/**
* 表示引用一个<sql>标签并执行<sql>标签中的sql查询语句。
*
* @author yonghuan
* @since 1.1.3
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
}
package com.topsunit.query.annotations;
import java.lang.annotation.*;
/**
* 表示引用一个sql标签。
*
* @author yonghuan
* @since 1.1.3
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Sql {
}
package com.topsunit.query.binding;
import com.huigou.data.query.executor.SQLExecutorDao;
/**
* 调用上下文。
*
* @author yonghuan
* @since 1.1.3
*/
public interface InvokeContext<T> {
/**
* 获取Mapper代理接口的类信息
*
* @return Mapper代理接口的类信息
*/
Class<T> getMapperInterface();
/**
* 获取 SQLExecutorDao。
*
* @return SQLExecutorDao
*/
SQLExecutorDao getSqlExecutor();
/**
* 获取配置xml文件。
*
* @return 配置xml文件
*/
String getXml();
}
package com.topsunit.query.binding;
import com.huigou.data.query.executor.SQLExecutorDao;
/**
* @author yonghuan
* @since 1.1.3
*/
final class InvokeContextImpl<T> implements InvokeContext {
private final Class<T> mapperInterface;
private final SQLExecutorDao sqlExecutor;
private final String xml;
public InvokeContextImpl(Class<T> mapperInterface, String xml, SQLExecutorDao sqlExecutor) {
this.mapperInterface = mapperInterface;
this.sqlExecutor = sqlExecutor;
this.xml = xml;
}
@Override
public Class<T> getMapperInterface() {
return mapperInterface;
}
@Override
public SQLExecutorDao getSqlExecutor() {
return sqlExecutor;
}
@Override
public String getXml() {
return xml;
}
}
package com.topsunit.query.binding;
import java.lang.reflect.Method;
/**
* 调用策略。
*
* @author yonghuan
* @since 1.1.3
*/
public interface InvokeStrategy {
/**
* 判断是否支持。
*
* @param invokeContext 执行上下文
* @param method 被调用的方法
* @param args 参数
* @return 如果支持就返回true, 否则返回false。
*/
boolean supports(InvokeContext invokeContext, Method method, Object[] args);
/**
* 执行。
*
* @param invokeContext 执行上下文
* @param method 被调用的方法
* @param args 参数
* @return 执行结果
*/
Object invoke(InvokeContext invokeContext, Method method, Object[] args);
}
package com.topsunit.query.binding;
import com.huigou.data.query.executor.SQLExecutorDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @param <T>
* @author yonghuan
*/
public class MapperProxy<T> implements InvocationHandler {
private final InvokeContext invokeContext;
private final List<InvokeStrategy> invokeStrategies;
public MapperProxy(Class<T> mapperInterface, String xml, SQLExecutorDao sqlExecutor) {
invokeContext = new InvokeContextImpl(mapperInterface, xml, sqlExecutor);
invokeStrategies = new ArrayList<>(4);
invokeStrategies.add(new SelectSqlInvokeStrategy());
invokeStrategies.add(new ObtainSqlInvokeStrategy());
invokeStrategies.add(new ObtainQueryDescriptorInvokeStrategy());
invokeStrategies.add(new SqlQueryInvokeStrategy());
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return invokeStrategies.stream()
.filter(invokeStrategy -> invokeStrategy.supports(invokeContext, method, args))
.map(invokeStrategy -> invokeStrategy.invoke(invokeContext, method, args))
.findFirst()
.get();
}
}
package com.topsunit.query.binding;
import com.huigou.data.query.executor.SQLExecutorDao;
import java.lang.reflect.Proxy;
/**
* @param <T>
* @author yonghuan
*/
public class MapperProxyFactory<T> {
private final SQLExecutorDao sqlExecutor;
private final Class<T> mapperInterface;
private final String xml;
public MapperProxyFactory(Class<T> mapperInterface, String xml, SQLExecutorDao sqlExecutor) {
this.sqlExecutor = sqlExecutor;
this.mapperInterface = mapperInterface;
this.xml = xml;
}
public T newInstance() {
MapperProxy<T> mapperProxy = new MapperProxy(mapperInterface, xml, sqlExecutor);
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
}
package com.topsunit.query.binding;
import com.topsunit.query.QueryDescriptorHolder;
import java.lang.reflect.Method;
/**
* 用于获取 {@link com.huigou.data.query.model.QueryDescriptor}。
*
* @author yonghuan
* @since 1.1.3
*/
final class ObtainQueryDescriptorInvokeStrategy implements InvokeStrategy {
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return QueryDescriptorHolder.class.isAssignableFrom(invokeContext.getMapperInterface())
&& "getQueryDescriptor".equals(method.getName())
&& method.getParameters().length == 1
&& method.getParameters()[0].getType() == String.class;
}
@Override
public Object invoke(InvokeContext invokeContext, Method method, Object[] args) {
return invokeContext.getSqlExecutor().getQuery(invokeContext.getXml(), (String) args[0]);
}
}
package com.topsunit.query.binding;
import com.huigou.data.query.model.QueryDescriptor;
import com.topsunit.query.annotations.Select;
import com.topsunit.query.annotations.Sql;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* 用于获取<sql>标签中的sql语句。
*
* @author yonghuan
* @see Sql
* @since 1.1.3
*/
class ObtainSqlInvokeStrategy implements InvokeStrategy {
private final static List<Class> COMPATIBLE_ANNOTATIONS = Arrays.asList(Select.class, Sql.class);
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return method.getAnnotation(Sql.class) != null;
}
@Override
public Object invoke(InvokeContext invokeContext, Method method, Object[] args) {
boolean compatible = COMPATIBLE_ANNOTATIONS.stream()
.filter(c -> method.getAnnotation(c) != null)
.findAny()
.isPresent();
if (!compatible) {
return null;
}
String[] queryNameAndSqlName = method.getName().split("\\$");
String queryName = queryNameAndSqlName[0];
String sqlName = queryNameAndSqlName[1];
QueryDescriptor queryDescriptor = invokeContext.getSqlExecutor().getQuery(invokeContext.getXml(), queryName);
return queryDescriptor.getSqlByName(sqlName);
}
}
package com.topsunit.query.binding;
import com.huigou.data.query.executor.SQLExecutorDao;
import com.topsunit.query.annotations.Param;
import com.topsunit.query.annotations.ResultType;
import com.topsunit.query.annotations.Select;
import org.apache.commons.lang.ArrayUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author yonghuan
* @see Select
* @since 1.1.3
*/
final class SelectSqlInvokeStrategy extends ObtainSqlInvokeStrategy {
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return method.getAnnotation(Select.class) != null;
}
@Override
public Object invoke(InvokeContext invokeContext, Method method, Object[] args) {
final String sql = (String) super.invoke(invokeContext, method, args);
final Class<?> returnType = method.getReturnType();
final SQLExecutorDao sqlExecutor = invokeContext.getSqlExecutor();
final ResultType resultType = method.getAnnotation(ResultType.class);
if (ArrayUtils.isEmpty(args)) {
// 无查询参数
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, resultType.value());
}
if (Map.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToMap(sql);
}
return resultType != null
? sqlExecutor.queryOneToObject(sql, resultType.value())
: sqlExecutor.queryOneToObject(sql, returnType);
}
if (args.length == 1) {
if (args[0] instanceof Map) {
// 查询参数用Map传递
return queryByMapParam(sqlExecutor, sql, returnType, resultType, (Map<String, Object>) args[0]);
} else {
// 单个查询参数
final Object singletonParam = args[0];
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, resultType.value(), singletonParam);
}
if (Map.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryOneToMap(sql, singletonParam);
}
return resultType != null
? sqlExecutor.queryOneToObject(sql, resultType.value())
: sqlExecutor.queryOneToObject(sql, returnType, singletonParam);
}
} else {
Parameter[] parameters = method.getParameters();
if (parameters[0].getAnnotation(Param.class) == null) {
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, returnType, args);
}
if (Map.class.isAssignableFrom(returnType)) {
sqlExecutor.queryOneToMap(sql, args);
}
return resultType != null
? sqlExecutor.queryOneToObject(sql, resultType.value(), args)
: sqlExecutor.queryOneToObject(sql, returnType, args);
} else {
// 指定了查询参数的名称
final Map<String, Object> mapParam = new HashMap<>(parameters.length);
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String paramName = parameter.getAnnotation(Param.class).value();
mapParam.put(paramName, args[i]);
}
return queryByMapParam(sqlExecutor, sql, returnType, resultType, mapParam);
}
}
}
private Object queryByMapParam(SQLExecutorDao sqlExecutor, String sql, Class<?> returnType, ResultType resultType, Map<String, Object> mapParam) {
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToListByMapParam(sql, returnType, mapParam);
}
if (Map.class.isAssignableFrom(returnType)) {
sqlExecutor.queryOneToMapByMapParam(sql, mapParam);
}
return resultType != null
? sqlExecutor.queryOneToObjectByMapParam(sql, resultType.value(), mapParam)
: sqlExecutor.queryOneToObjectByMapParam(sql, returnType, mapParam);
}
}
package com.topsunit.query.binding;
import com.huigou.cache.DictUtil;
import com.huigou.data.domain.query.QueryAbstractRequest;
import com.huigou.data.domain.query.QueryPageRequest;
import com.huigou.data.query.model.QueryDescriptor;
import com.huigou.data.query.model.QueryModel;
import com.huigou.util.ClassHelper;
import com.huigou.util.Constants;
import com.topsunit.query.annotations.Dictionary;
import com.topsunit.query.annotations.Param;
import com.topsunit.query.annotations.ResultType;
import net.sf.cglib.beans.BeanGenerator;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 用于执行<sql-query>标签中的语句。
*
* @author yonghuan
* @since 1.1.3
*/
final class SqlQueryInvokeStrategy implements InvokeStrategy {
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return true;
}
@Override
public Object invoke(InvokeContext invokeContext, Method method, Object[] args) {
List<QueryAbstractRequest> requests = ArrayUtils.isEmpty(args)
? new ArrayList<>(1)
: Arrays.stream(args).filter(arg -> arg instanceof QueryAbstractRequest)
.map(arg -> (QueryAbstractRequest) arg)
.collect(Collectors.toList());
if (requests.size() > 1) {
throw new IllegalArgumentException("只能设置一个自定QueryRequest");
}
if (requests.isEmpty()) {
requests.add(generateQueryProxy(method, args));
}
QueryAbstractRequest query = requests.get(0);
String queryName = method.getName();
QueryDescriptor queryDescriptor = invokeContext.getSqlExecutor().getQuery(invokeContext.getXml(), queryName);
QueryModel model = invokeContext.getSqlExecutor().getQueryModel(queryDescriptor, query);
// 解析字典配置
for (Dictionary dictionary : method.getAnnotationsByType(Dictionary.class)) {
if (StringUtils.isNotEmpty(dictionary.value()) && StringUtils.isNotEmpty(dictionary.field())) {
model.putDictionary(dictionary.field(), DictUtil.getDictionary(dictionary.value()));
}
}
final QueryPageRequest pageModel = query.getPageModel();
final boolean needPage = pageModel != null
&& pageModel.getPageIndex() != null
&& pageModel.getPageSize() != null;
Map<String, Object> result = needPage ? invokeContext.getSqlExecutor().executeSlicedQuery(model)
: invokeContext.getSqlExecutor().executeQuery(model);
Class<?> retType = method.getReturnType();
if (Map.class.isAssignableFrom(retType)) {
return result;
}
if (Collection.class.isAssignableFrom(retType)) {
List<Map<String, Object>> rows = (List<Map<String, Object>>) result.get(Constants.ROWS);
ResultType resultType = method.getAnnotation(ResultType.class);
return resultType == null
? rows
: rows.stream().map(row -> ClassHelper.fromMap(resultType.value(), row)).collect(Collectors.toList());
}
if (Page.class.isAssignableFrom(retType)) {
List<?> rows = (List<?>) result.get(Constants.ROWS);
long total = ((Number) result.getOrDefault(Constants.RECORD, rows.size())).longValue();
return needPage
? new PageImpl(rows, new PageRequest(pageModel.getPageIndex() - 1, pageModel.getPageSize()), total)
: new PageImpl(rows);
}
throw new IllegalArgumentException(String.format("无法转换查询结果集为:%s", retType.getName()));
}
private QueryAbstractRequest generateQueryProxy(Method method, Object[] args) {
BeanGenerator queryGenerator = new BeanGenerator();
queryGenerator.setSuperclass(QueryAbstractRequest.class);
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
Class parameterType = parameter.getType();
if (Collection.class.isAssignableFrom(parameterType)) {
parameterType = String.class;
}
queryGenerator.addProperty(paramAnnotation.value(), parameterType);
}
}
QueryAbstractRequest queryProxy = (QueryAbstractRequest) queryGenerator.create();
PropertyDescriptor[] propertyDescriptors;
try {
propertyDescriptors = Introspector.getBeanInfo(queryProxy.getClass()).getPropertyDescriptors();
} catch (IntrospectionException ie) {
throw new IllegalArgumentException(ie);
}
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Param paramAnnotation = parameter.getAnnotation(Param.class);
if (paramAnnotation != null) {
String paramName = paramAnnotation.value();
PropertyDescriptor propertyDescriptor = Stream.of(propertyDescriptors)
.filter(pd -> pd.getName().equals(paramName))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询参数 %s", paramName)));
Object paramVal = args[i];
if (paramVal instanceof Collection) {
Collection<?> items = (Collection<?>) paramVal;
paramVal = items.stream().map(String::valueOf).collect(Collectors.joining(","));
}
try {
propertyDescriptor.getWriteMethod().invoke(queryProxy, paramVal);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException(String.format("绑定参数 paramName=%s,paramValue=%s 时候出错", paramName, paramVal), e);
}
}
}
return queryProxy;
}
}
package com.topsunit.query.spring.mapper;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author yonghuan
*/
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
private String sqlExecutorBeanName;
private Class<? extends Annotation> annotationClass;
private Class<?> markerInterface;
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public String getSqlExecutorBeanName() {
return sqlExecutorBeanName;
}
public void setSqlExecutorBeanName(String sqlExecutorBeanName) {
this.sqlExecutorBeanName = sqlExecutorBeanName;
}
public Class<? extends Annotation> getAnnotationClass() {
return annotationClass;
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}
public Class<?> getMarkerInterface() {
return markerInterface;
}
public void setMarkerInterface(Class<?> markerInterface) {
this.markerInterface = markerInterface;
}
public Class<? extends MapperFactoryBean> getMapperFactoryBeanClass() {
return mapperFactoryBeanClass;
}
public void setMapperFactoryBeanClass(Class<? extends MapperFactoryBean> mapperFactoryBeanClass) {
this.mapperFactoryBeanClass = mapperFactoryBeanClass != null ? mapperFactoryBeanClass : MapperFactoryBean.class;
}
public void registerFilters() {
boolean acceptAllInterfaces = true;
// if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
}
// override AssignableTypeFilter to ignore matches on the actual marker interface
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
}
// exclude package-info.java
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.size() > 0) {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
definition.setBeanClass(this.mapperFactoryBeanClass);
definition.getPropertyValues().add("sqlExecutor", new RuntimeBeanReference(sqlExecutorBeanName));
definition.setLazyInit(true);
}
}
@Override
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
candidates.add(sbd);
} else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
} else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
}
package com.topsunit.query.spring.mapper;
import com.huigou.data.query.executor.SQLExecutorDao;
import com.topsunit.query.annotations.Mapper;
import com.topsunit.query.binding.MapperProxyFactory;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.Resource;
import io.github.classgraph.ScanResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.FactoryBean;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
/**
* @param <T>
* @author yonghuan
*/
public class MapperFactoryBean<T> implements FactoryBean<T> {
private final static String MAPPER_SUFFIX = "Mapper";
private final static int MAPPER_SUFFIX_LENGTH = MAPPER_SUFFIX.length();
private SQLExecutorDao sqlExecutor;
private Class<T> mapperInterface;
public MapperFactoryBean() {
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public SQLExecutorDao getSqlExecutor() {
return sqlExecutor;
}
public void setSqlExecutor(SQLExecutorDao sqlExecutor) {
this.sqlExecutor = sqlExecutor;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
Mapper mapper = mapperInterface.getAnnotation(Mapper.class);
String xml = mapper.xml();
if (StringUtils.isBlank(xml)) {
// 未指定查询xml文件,将自定匹配
String interfaceName = mapperInterface.getSimpleName();
interfaceName = Character.toLowerCase(interfaceName.charAt(0)) + interfaceName.substring(1);
List<String> mapperXmlPatterns = new ArrayList<>(2);
mapperXmlPatterns.add(String.join(".", interfaceName, "xml"));
if (interfaceName.endsWith(MAPPER_SUFFIX)) {
String name = interfaceName.substring(0, interfaceName.length() - MAPPER_SUFFIX_LENGTH);
mapperXmlPatterns.add(name + ".xml");
}
xml = mapperXmlPatterns.stream()
.map(this::findMapperXml)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询xml文件 %s", mapperInterface.getSimpleName())));
}
MapperProxyFactory<T> factory = new MapperProxyFactory<>(mapperInterface, xml, sqlExecutor);
return factory.newInstance();
}
private Optional<String> findMapperXml(String file) {
try (ScanResult scanResult = new ClassGraph().scan()) {
return scanResult.getResourcesWithExtension("xml").stream()
.map(Resource::getPath)
.filter(f -> f.endsWith(file))
.sorted(Comparator.comparing(String::length).reversed())
.findFirst();
}
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
}
package com.topsunit.query.spring.mapper;
import com.topsunit.query.annotations.Mapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
/**
* @author yonghuan
*/
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
private String sqlExecutorBeanName;
private final Class<? extends Annotation> annotationClass = Mapper.class;
private String basePackage;
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass;
public String getSqlExecutorBeanName() {
return sqlExecutorBeanName;
}
public void setSqlExecutorBeanName(String sqlExecutorBeanName) {
this.sqlExecutorBeanName = sqlExecutorBeanName;
}
public String getBasePackage() {
return basePackage;
}
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public Class<? extends MapperFactoryBean> getMapperFactoryBeanClass() {
return mapperFactoryBeanClass;
}
public void setMapperFactoryBeanClass(Class<? extends MapperFactoryBean> mapperFactoryBeanClass) {
this.mapperFactoryBeanClass = mapperFactoryBeanClass;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setSqlExecutorBeanName(sqlExecutorBeanName);
scanner.setAnnotationClass(annotationClass);
scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
Markdown is supported
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