Appearance
如何编写后台代码
低代码平台自定义后台代码有多种模式,一般业务开发只需要熟悉两种形态的自定义业务即可。* 一种是定义一个业务BO类,定义到工作流(反馈流)中,执行通用系统事件后会根据业务定义的参数在事件事件前、事件后执行。
- 一种是独立定义一个服务Controller,供自定义业务独立实现,这个只需要熟悉系统如何操作数据库、如何创建事务、如何利用一些通用工具类即可;
- 重点注意的是数据源切换方法;
- 要掌握两种操作数据表的方法,mapper和sqlmapper。当使用sqlmapper时切记必须关闭数据连接session。
- 掌握事务使用
1. 数据源切换
- 操作Mapper前:
java
DynamicDataSource.setDataSource(dbSource);//设置指定数据源
操作后清除:
java
DynamicDataSource.clearDataSource();//清理
2. 两种数据表的操作方法
- Mapper法
- 注解注入Mapper也可以:
java
@Autowired
privateToolFunctionEventSqlMappertoolFunctionEventSqlMapper;
- 手工注入也可以:
java
BaseService.getMapper("ToolFunction").selectAll();
- SQLMapper法
通过制定数据源创建sqlsession,然后创建sqlmapper对象,
java
SqlSessionsession=getSession(dbSource);
SqlMappersqlMapper=newSqlMapper(session);
List<Map<String,Object>>rowList=sqlMapper.selectList(SQLPageHelper.SqlPage(getDBType(dbSource),selectSQL+fromSQL+whereSQL,orderBySQL),requestMap);
使用后一定要在finally里关闭session
java
}catch(Exceptione){
log.error("查询sql出错!",e);
Throw newException(e);
}finally{
session.close();
}
3. 事务使用:
在类的前面注入初始化事务对象
java
@Autowired
publicPlatformTransactionManagertransactionManager;
在方法体里,启用事务
java
DefaultTransactionDefinitiondef=newDefaultTransactionDefinition();
/*PROPAGATION_REQUIRES_NEW:事物隔离级别,开启新事务*/
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatusstatus=transactionManager.getTransaction(def);
完成业务后提交事务
java
transactionManager.commit(status);
利用try,将方法体异常捕捉好,异常情况rollback事务。
java
}catch(Exceptione){
transactionManager.rollback(status);
log.error("事件执行出错",e);
returnResult.failure("500","事件执行出错");
}finally{
DynamicDataSource.clearDataSource();//清理
log.info("cleandatasource");
}
4. BO案例
java
Package com.grgbanking.business.pm; //根据命名规范放到规定目录即可
Import com.grgbanking.config.DynamicDataSource;
Import com.grgbanking.core.BaseEntity;
Import com.grgbanking.core.BaseService;
Import com.grgbanking.core.utils.E2MapUtil;
Import com.grgbanking.core.utils.Map2EntityUtil;
Import com.grgbanking.core.vo.Result;
Import com.grgbanking.modules.pm.entity.PmRecordDaily;
Import com.grgbanking.modules.util.DateUtil;
Import lombok.extern.slf4j.Slf4j;
Import org.apache.commons.lang3.time.DateUtils;
Import java.util.Date;
Import java.util.HashMap;
Import java.util.List;
Import java.util.Map;
/**
*@author[Yonsin]on[2020/9/1]
*@Description:[功能描述]
*@ModifiedBy:[修改人]on[修改日期]for[修改说明]
*/
@Slf4j
Public class PmUserTimeBO{ //无需继承或重写任何方法
Public Result`<?>compute(Map<String,Object>mp)throwsException{ //必须要返回 Result<?>`对象,方法参数必须是Map<String,Object>
for(Map.Entry<String,Object>entry:mp.entrySet()){
log.info("computeKey="+entry.getKey()+",Value="+entry.getValue());
}
Stringdaily_id=(String)mp.get("daily_id");
Stringuser_id=(String)mp.get("user_id");
Objectrecord_date=mp.get("record_date");
//不能直接对象操作,这样热加载修改对象还是拿到旧对象
PmRecordDailyquery=newPmRecordDaily();
query.setUser_id(user_id);
if(null!=record_date)query.setRecord_date(record_dateinstanceofDate?(Date)record_date:(record_dateinstanceofLong?newDate((Long)record_date):DateUtil.parse((String)record_date)));
//
try{
DynamicDataSource.setDataSource("pm"); //标记切换数据源
List`<PmRecordDaily>`ls=BaseService.getMapper("PmRecordDaily").select(query); //BaseService.getMapper创建Mapper对象
DynamicDataSource.clearDataSource();
if(ls!=null&&ls.size()!=0){
Doublemax=0.0;
for(PmRecordDailydaily:ls){
Doubletime=daily.getTask_time();
if(time==null)time=0.0;
max+=time;
}
log.info("max======"+String.valueOf(max));
if(max>24)
Return Result.failure("500","当日累计工时【"+(Math.round(max*100)/100)+"】超过一天24小时,请确认工时是否正确!");
}
}catch(Exceptione){
Return Result.failure("500","PmUserTimeBO计算累计工时出现未知错误!");
}
Return Result.success();
}
}
5. Controller案例
java
Package com.grgbanking.modules.tool.web;
Import com.alibaba.fastjson.JSON;
Import com.alibaba.fastjson.JSONArray;
Import com.alibaba.fastjson.JSONObject;
Import com.grgbanking.MemCache;
Import com.grgbanking.config.DynamicDataSource;
Import com.grgbanking.core.BaseController;
Import com.grgbanking.core.TreeBean;
Import com.grgbanking.core.utils.*;
Import com.grgbanking.core.vo.Result;
importcom.grgbanking.modules.tool.entity.ToolFunction;
Import lombok.extern.slf4j.Slf4j;
Import org.apache.commons.lang.StringEscapeUtils;
Import org.springframework.stereotype.Controller;
Import org.springframework.ui.Model;
Import org.springframework.web.bind.annotation.GetMapping;
Import org.springframework.web.bind.annotation.RequestMapping;
Import org.springframework.web.bind.annotation.RequestParam;
Import org.springframework.web.bind.annotation.ResponseBody;
Import javax.servlet.http.HttpServletRequest;
Import javax.sql.DataSource;
Import java.io.File;
Import java.nio.file.Files;
Import java.nio.file.Path;
Import java.nio.file.Paths;
Import java.nio.file.attribute.BasicFileAttributes;
Import java.sql.*;
Import java.util.ArrayList;
Import java.util.HashMap;
Import java.util.List;
Import java.util.Map;
/**
*@Description:IMS
*@author[Yonsin]on[2020年11月11日上午10:39:37]
*@ModifiedBy:[修改人]on[修改日期]for[修改说明]
*/
@Slf4j
@Controller
@RequestMapping("/filemanager")
Public classToolFIleManagerControllerextendsBaseController{ //继承BaseController
@ResponseBody
@RequestMapping("/dirTree")
Public List`<TreeBean>`dirTree(HttpServletRequestrequest)throwsException{ //前端树控件要求返回对象为List`<TreeBean>`,这样能直接替代通用树方法
Map<String,Object>requestMap=Map2EntityUtil.request2Map(request);// //一般建议所有方法都是直接Request来接收,然后根据这个Map转换工具类来转换为Map对象
log.info("/filemanager/dirTreebegin:");
StringdirPath=(String)requestMap.get("dirPath");
//拼装树型数据对象
List`<TreeBean>`result=newArrayList`<TreeBean>`();
if(StringUtils.isEmpty(dirPath))returnresult;
try{
Filedir=newFile(dirPath);
log.info("dirPath:"+dirPath+"=="+dir.isDirectory());
if(dir.isDirectory()){
File[]files=dir.listFiles();
for(Filefile:files){
if(file.isDirectory()){
TreeBeanbean=newTreeBean();
//根据设置来取真实值
Stringid=file.getAbsolutePath();
bean.setId(id);
bean.setPId(dirPath);
File[]subfiles=file.listFiles();
Boolean hasSub=false;
Int fileNum=0;
for(Filesubfile:subfiles){
if(subfile.isDirectory()){
hasSub=true;
}else{
fileNum++;
}
}
bean.setParent(hasSub);
//显示值
bean.setName(file.getName()+(fileNum>0?"["+fileNum+"]":""));
result.add(bean);
}
}
}
}catch(Exceptione){
log.error("获取目录结构报错!",e);
}
Return result;
}
@ResponseBody
@RequestMapping("/getFileList")
Public Result<?>getFileList(HttpServletRequestrequest)throwsException{ //一般的前端Jquery方法调用后台会统一返回Result对象
Map<String,Object>requestMap=Map2EntityUtil.request2Map(request);//
for(Map.Entry<String,Object>entry:requestMap.entrySet()){
log.info("Key="+entry.getKey()+",Value="+entry.getValue());
}
StringdirPath=(String)requestMap.get("dirPath");
Resultresult=Result.success();
List<Map<String,String>>datals=newArrayList<Map<String,String>>();
try{
Filedir=newFile(dirPath);
File[]files=dir.listFiles();
for(Filefile:files){
if(file.isDirectory())continue;
Map<String,String>mp=newHashMap<String,String>();
mp.put("file_name",file.getName());
mp.put("file_path",file.getAbsolutePath());
mp.put("file_size",FileUtils.getPrintSize(file.length()));
Pathp=Paths.get(file.getAbsolutePath());
BasicFileAttributesatt=Files.readAttributes(p,BasicFileAttributes.class);//获取文件的属性
mp.put("create_time",DateUtils.formatDateTime(newDate(att.creationTime().toMillis())));
mp.put("lastmodified_time",DateUtils.formatDateTime(newDate(att.lastModifiedTime().toMillis())));
datals.add(mp);
}
result.setData(datals);
}catch(Exceptione){
log.error("获取文件列表报错!",e);
result.setSuccess(false);
result.setCode("500");
result.setMsg(e.getMessage());
}
Return result;
}
/**
*获取codeEditor文件内容
*@paramrequest
*@return
*/
@ResponseBody
@RequestMapping("/getFileContent")
Public Result<?>readFileContent(HttpServletRequestrequest){
Map<String,Object>requestMap=Map2EntityUtil.request2Map(request);//
Stringfilepath=(String)requestMap.get("filepath");
//StringfunId=(String)requestMap.get("funId");
log.info("codeEditor::::::"+filepath);
StringBuilderfilebody=newStringBuilder("");
if(StringUtils.isEmpty(filepath)){
Return Result.failure("500","文件路径不能为空!");
}
try{
filebody=FileUtils.readFile2String(filepath);
}catch(Exceptione){
log.error("",e);
}
Resultresult=newResult();
result.setData(filebody.toString());
result.setSuccess(true);
Return result;
}
/**
*保存codeEditor文件内容
*@paramrequest
*@return
*/
@ResponseBody
@RequestMapping("/saveFileContent")
Public Result<?>saveFileContent(HttpServletRequestrequest){
Map<String,Object>requestMap=Map2EntityUtil.request2Map(request);//
Stringfilepath=(String)requestMap.get("filepath");
log.info("codeEditor::::::"+filepath);
if(StringUtils.isEmpty(filepath)){
Return Result.failure("500","文件路径不能为空!");
}
Stringfilecontent=(String)requestMap.get("filecontent");
filecontent=StringEscapeUtils.unescapeHtml(filecontent);
Stringallpath=filepath.substring(0,filepath.lastIndexOf("/")+1);
Stringnewfilename=filepath.substring(filepath.lastIndexOf("/")+1);
FileUtils.createUTF8File(allpath,newfilename,filecontent,false);
Resultresult=newResult();
result.setMsg("保存成功!");
result.setSuccess(true);
Return result;
}
}