admin后台代码通用封装
#重点封装类
CommonDao
/*
如果在mycat分库分表的情况下,可以提供多个方法支持不同分片算法的数据crud,这里演示较为常用的查询,即非复合分片的CRUD实现
@mapper:使用该注解,结合@select等标签来省略配置文件
*/
public interface CommonDao{
//不带条件查询所有
@Select("select *from ${tableName} limit #{start} ,#{ size}")
@ResultType(HashMap.class)
List<HashMap> list(@param("tableName")String tableName,@param("start")int start,@param("size")int size)
//根据list查询count总数
@Select("select count(*) from ${tableName}")
@ResultType(Integer.class)
int listCount(@param("tableName")String tableName);
//根据条件查询list
@Select("select * from ${tableName} where 1=1 ${where} limit #{start} ,#{size}") //where ==> and name = 11 and password = ddd
@ResultType(HashMap.calss)
List<HashMap> listForWhere(@param("tableName") String tableName,@param("where") String where,@param(“start”) int start , @Param(size) int size);
//ListCountForWhere
@Select("select count(*) from ${tableName} where 1=1 ${where}") //where ==> and name = 11 and password = ddd
@ResultType(HashMap.calss)
//不需要分页了
int listCountForWhere(@param("tableName") String tableName,@param("where") String where);
//修改,返回修改了多少行 ,where是条件, sets中存放的是值
@Update("update ${tableName} set ${sets} where 1=1 ${where }")//set ⇒ name=xxx ,password =xsdfd
@ResultType(Integer.class)
int update(@param("tableName") String tableName,@param("where") String where, @param("sets")String sets)
@Insert("insert into ${tableName} (${fileds} values(${valuse})")
@ResultType(Integer.class)
int insert(@param("tableName") String tableName ,@param("")String fileds ,Stirng values)
//这里在拼接表名的时候一定要使用$符号,因为$符号是拼接,而#号是
@Delete("delete from ${tableName} where 1= 1 $ {where} limit 1")
@ResultType(Integer.class)
int delete(@param("tableName") String tableName, @param("where") String where)
}
在完成动态方法的编写之后,我们需要加上@mapper注解,将通用的dao加入到管理容器当中的,用于serice层的注入。同时在我们的编写sqlConfig中添加@mapperConfig将该类识别为一个mapper。
编写完通用的service之后,编写一个通用的service:
public interface CommonService{
//加载通用的数据列表 ,包括了我们的无条件查询,无条件的统计 有条件的统计 有条件的统计
ResponseResult list(CommonDto dto);
//修改该通用的数据列表,新增也使用这个方法,利用dto中的model属性进行区分。
ResponseResult update(CommonDto dto);
//删除通用的数据列表
ResponseResult delete(CommonDto dto);
}
编写service的是实现类commonServcieImpl类,实现通用的CRUD的业务处理
parseValue: 方法过滤和替换引起SQL注入的关键字符;注filed和value都需要过滤
doFilter:用于依据name查找对应后置增强的Bean,如果查得,则执行对应增强的后置处理
getWhere:拼接where条件字符串,支持like,between,=等条件查询
getSets:拼接修改的set语句的值
getInsertSql:拼接新增Sql的字段和值的字符串。
public class CommonServiceImpl implement Commservice{
private CommonDao commondao;
private ApplicationContext context;
//加载通用的数据列表 ,包括了我们的无条件查询,无条件的统计 有条件的统计 有条件的统计
ResponseResult list(CommonDto dto){
//先判断对应的表是否具有加载列表的权限,拿到具体对应的某一张表
if(dto.getName().isList){
return ResponseResult.errorResult(AppHttpCodeEunm.NO_OPERATOR_AUTH);
}
//查询,有可能会有条件,条件汆子啊CommonDto当中,查询的时候呀我们使用的where.
getWhere(dto);
String tableName=dto.getName().name().toLowerCase();
//起始值
int start = (dto.getPage()-1)*dto.getSize();
if(start<-1){
start = 0;
}
list<?> list =null;
int total=0;
//判断是带条件查询还是不带条件查询,根据两者的不同,调用不同的方法
if(StringUtils.isEmpty(where)){
list =commonDao.list(tableName,dto.getPage(),dto.getSize());
total=commonDao.listCount(tableName);
}else{
//带条件的查询
list = commonDao.listForWhere(talbeName,where,start,dto.getSize());
total = commonDao.listCountForWhere(tableName,where);
} //返回的话,统一返回map,里面封装着list和total;
Map<String,Object> map=new HashMap<>();
map.put("list",list);
map.put("total",total);
//后处理的bean
doFilter(dto,"list");
retrun ResponseResult.okResult(map);
};
//我们当前只有接口,没有现实类,如果谁要做后置逻辑的和增强,谁就去实现这个接口。
private void doFilter(CommonDto dto,String list){
BaseCommonFilter baseCommonFilter=findFilter(dto);
if(baseCommonFilter!=null){
//处理具体的方法
AUser adUser= AdminThreadLocalUtils.getUser();
if("insert".equals(name)){
baseCommonFilter.doInsertAfter(adUser,dto);
}
if("update".equal(name)){
baseCommonFilter.doupdatetAfter(adUser,dto);
}
if("list".equal(name)){
baseCommonFilter.doListAfter(adUser,dto);
}
if("delete".equal(name)){
baseCommnFilter.doDeleteAfter(adUser,dto);
}
}
}
//从spirng容器当中获取当前的Filter
private BaseCommonFilter findFilter(commonDto dto){
String name=dto.getName().name();
//这里为什么不能直接注入,是因为filter是由需要增强的对象自己编写的,是需要在运行的过程中手动的判断
if(context.containsBean(name)){
return context.getBean(name.BaseCommonFilter.class);
}
return null;
}
//拼接查询条件来用的,通过dto拿到dto,然后进行循环,然后在循环的的时候拿到各个字段,在循环的时候去拼接各个字符串
private String getWhere(CommonDto dto){
StringBuffer where= new StringBuffer;;
if(dto.getWhere()!=null){
dto.getWhere.stream().forEach(w->{
//防止sql注入,以及字段为空,字段的值不能相等,所以field不能等于value;
if(StringUtlis.isNotEmpty(w.getFiled())&&StringUtils.isNotEmpty(w.getValue())&&!w.getFiled().equalsIgnoreCase(w.getValue())){
//这里已经拿到了field的值了,直接拼接sql不就行了嘛;
String tempF=parseValue(w.getFiled());
String tempV=parseValue(w.getValue());
//filed当中不能是光有数字,而且经过防sql注入的过滤之后,filed和value也是不能相等
if(!tempF.matches("\\d*")&&!tempF.equalsIgnoreCase(tempV)){
if("eq".eqy)
where.append(" and ").append(tempF).append("= \'").append(tempV).append("\'");
if("like".equals(w.getType())){
where.append(" and ").append(tempF).append("like \'%").append(tempV).append("%\'");
if("bwtween".equals(w.getType())){
String[] temp=tempV.split(",");
where.append(" and " ).append(tempF).append(temp[0]).append(" and ").append(tempF).append(temp[0]).append(" and ").append(temp[1]);
}
}
}
}
});
}
}
//修改该通用的数据列表,新增也使用这个方法,利用dto中的model属性进行区分。
ResponseResult update(CommonDto dto){
String model=dto.getModel();
String tableName=dto.getName.name().tolowerCase();
if("add".equals(model)){
//新增,新增需不要加where,不需要,如果传入的dto当中存在
if(StringUtils.isNotEmpty(where)){
return ResponseResult.errorResult(AppHttpCodeEnum.PARA_INVALID,"新增数据不能设置条件");
}else{
//插入一条数据的方法。
return addData(dto,talbeName,update);
}
}else{
//修改
if(StringUtils.isEmpty){
return Response.errorResult(AppHttpCodeEunm.PARA_INVALID,"修改田条件不能为空");
}
return updateData(dto,tableName);
}
return null;
}
//删除通用的数据列表
ResponseResult delete(CommonDto dto){
String where=getWhere(dto)
String TableName=dto.geName().name().toLowerCase
if(!dto.getName().isDelete()){
return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPEATOR_AUTH);
}
if(StringUtils.isEmpty(where)){
return ResponseResult.errorResult(AppHttpCodeEnum.PRAM_INVALID,"删除条件不合法");
int temp=commonDao.delete(tableName,where);
if(temp>0){
doFilter(dto,"delete");
}
return Response.okResult(temp);
}
}
//为了防止sql注入,我们需要替换一些敏感的符号,就是对filed做一个判断,使用正则表达式,将可能出现的,w.getValue()
private String parseValue(String field){
if(StringUtils.isNotEmpty(filed){
return filed.replaceAll(".*([';#%+|(--)]).*","");
}
return field;
}
//新增逻辑
private ResponseResult addData(CommonDto dto ,String talbeName){
String[] sql=getInsertSql(dto);
if(!dto.getName().isAdd()){
return ResponseResult.errorResult(AppHttpCodeEnum.No_OPreator_auth);
} if(sql==null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"传入的参数值不能为空");
int temp =commDao.insert(tableName,sql[0],sql[1]);
if(temp>0){
doFilter(dto,"add");
}
return ResponseResult.okResult(temp);
}
}
private String[] getInsertSql(CommonDto dto){
//拼接插入的字符串
StringBuffer fileds=new StringBuffer();
StringBufer values =new StringBuffer():
AtomicInteger count=new AtomicInteger();
if(dto.getSets()!=null){
dto.getSets().stream().forEach(
w->{
if(StringUtils.isEmpty(w.getVaule())){
//后期我们来判断这个count,如果count有值,则表示sql语句中存在为空的情况,我们就不能正常返回这个sql语句。
count.incrementAndGet();
}
else{
//匹配替换当前的单引号,百分号,注释,
String tempF=parseValue(w.getFiled());
String tempV=paraseValue(w.getValue())
if(!tempF.matches("\\d*")&&!tempF.equlasIgnoreCase(tempV)){
if(fileds.lenth>0){
fileds.append(",");
values.append(",");
}
fileds.append(tempF);
values.append("\'").append(tempV).append("\'");
//name,password,item -- > 'zhangsan','123','sss'
}
}
});
}
if(count.get()>0){
return null;
}
return new String[]{fileds.toStirng,values.toStirng()};
}
//更新一条数据
private ResponseResult updateData(CommonDto dto,String tableName,String where){
String sets=getSets(dto);
if(dto.getName().isUpdate()){
return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPREARTOR_AUTH);
}
if(StringUtils.isEmpty(sets)){
return ResponseResult.errorResult(ApphttpCodeEnum.PARA_INVALID,"修改的参数值不能为空");
}
int temp = commonDao.update(tableName,where,sets);
if(temp>0){
doFilter(dto,"update");
}
retrun ResponseResult.oKResult(temp)}
//拼接更新条件 where ,sets set ==>name=xxx ,password=xsdfaf;
private String getSets(CommonDto dto){
StringBuffer sets=new StringBuffer();
AtomicInteger count=new AtomicInteger();
if(dto.getSets()!=null){
dto.getSets.stream.forEach(w->{
if(StringUtils.isEmpty(w.getValue())){
cout.increamentAndGet();
}else{
String tempF=parseValue(w.gertFiled());
String tempV=praseValue(w.getValue());
if(!tempF.matches("\\d*")&&tempF.equalsIsIgnoreCase(tempV)){
if(sets.lenth()>0){
set.append(",");
}
sets.append(tempF).append("='/'").append(tempV).append("\'");
}
}
});
}
if(count.get()>0){
retrun null;
}
return sets.toString();
}
}
CommonDto类.这里封装的dto类,是由前端封装过来的。
public class CommonDto{
private Integer size;
private Integer page;
private String model;
private CommonTableEunm name;
private List<CommonTableEunm> where;
private List<CommonWhereDto> sets;
}
//CommonWhereDto类
public class CommonWhereDto{
}
Controller端的编写:
CommonController:
@RestController
@RequestMapping("/api/v1/admin/common")
public class CommonController{
@Autowired
private CommonService commonService;
@PostMapping("/list")
public ResponseResult list(@RequestBody commonDto dto){
return commonService.list(dto);
}
@PostMapping("/update")
public ResponseResult update(@RquestBody CommonDto dto){
return commonService.update(dto);
}
}