工作流
方法
- 重写了这个方法就默认是用自己的xml,不会使用默认的beforeQueryData方法
@Override
protected boolean multiTable() {
return true;
}
- afterQueryData:在获取列表数据源后,可以在这里对数据进行加工。
@Override
protected void afterQueryData(PagerInfo<TrainRecord> pagerInfo) {
List<TrainRecord> records = pagerInfo.getRecords();
Iterator<TrainRecord> iterator = records.iterator();
while(iterator.hasNext()){
TrainRecord trainRecord = iterator.next();
List<TrainRecordDetailed> trainRecordDetailedList = trainRecordDetailedService.lambdaQuery().eq(TrainRecordDetailed::getRecordId,trainRecord.getRecordId()).list();
trainRecord.setDomains(trainRecordDetailedList);
}
}
- beforeQueryData:页面初始化数据的时候,排序,模糊查询
@Override
protected void beforeQueryData(ListQueryParser parser) {
parser.map("createUserName", Operator.like);
parser.map("planName", Operator.like);
parser.setDefaultOrderColumnDesc("create_time");
super.beforeQueryData(parser);
}
- beforeSave保存前,新增页面进入的方法,保存生成编号
@Override
protected boolean beforeSave(StaffSupervisionPlan entity, boolean isNew) throws Exception {
if (isNew) {
entity.setStatus(StaffSupervisionProcessStatusEnum.UNCOMMITTED.getValue());
entity.setPlanType(0);
entity.setPlanCode(codeGeneratorService.codeGenerator(BusinessCodeTypeEnum.PROJECT_RJ));
}
return super.beforeSave(entity, isNew);
}
- getExcludeProperties:排除数据库没有的字段
/**
* 插入或更新实体时要排除的字段,不从 request 中更新这几个字段。如果在 includeProperties中也定义了些字段,则 includeProperties 优先。由子类定义;
*
* @return
*/
@Override
protected List<String> getExcludeProperties() {
List<String> list = new ArrayList<>();
list.add("supervisorUserIds");
list.add("supervisedUserIds");
list.add("projectIds");
list.add("supervisionContentIds");
return list;
}
- 根据id获取loginId
users.add(iSysUserService.getById(formData.getSubscriberId()).getLoginId());
- onBeforeBackward:工作流撤回进入此方法
@Override
protected boolean onBeforeBackward(String backwardTaskCode, ActExtWorkItem targetWorkItem) {
WorkflowContext context = getWorkflowContext();
TrainPlan formData = (TrainPlan) context.getFormData();
switch (targetWorkItem.getTaskCode()) {
case "usertask1":
formData.setStatus(TrainPlanStatusEnum.COMMITTED.getValue());
break;
case "usertask2":
formData.setStatus(TrainPlanStatusEnum.COMPREHENSIVE_ROOM_DEPARTMENT_MANAGER_EXAMINE.getValue());
break;
case "usertask3":
formData.setStatus(TrainPlanStatusEnum.TECHNICAL_DIRECTOR_REVIEW.getValue());
break;
case "usertask4":
formData.setStatus(TrainPlanStatusEnum.INPUT_TRAIN_RECORD.getValue());
break;
case "usertask5":
formData.setStatus(TrainPlanStatusEnum.INPUT_TRAIN_RECORD.getValue());
break;
case "usertask6":
formData.setStatus(TrainPlanStatusEnum.FINANCE_REVIEW.getValue());
break;
case "usertask7":
formData.setStatus(TrainPlanStatusEnum.INPUT_TRAIN_RECORD.getValue());
break;
default:
break;
}
return super.onBeforeBackward(backwardTaskCode, targetWorkItem);
}
- 工作流传阅
/**
* 传阅给综合室主任
* @param taskId
*/
public void doNotify(String taskId) {
// 获取综合室主任useId
List<String> userIdList = iSysUserService.listUserIdsByRoleCode("COMPREHENSIVE_ROOM_DEPARTMENT_MANAGER");
String userIds = StringUtils.join(userIdList,",");
if(StringUtils.isNotBlank(userIds)){
actExtWorkItemService.processDoNotify(taskId, userIds);
}
}
- 删除方法
@PostMapping("/remove")
public Result remove(@RequestBody ArrayList<Long> ids) {
baseService.lambdaUpdate()
.set(Supplier::getIsDeleted,true)
.eq(Supplier::getStatus, SupplierStatusEnum.DEFAULT_STATUS.getValue())
.in(Supplier::getSupplierId,ids)
.update();
return Result.ok();
}
- 查询工作流流程sql
select
distinct RES.*
from
ACT_RU_TASK RES
where
RES.PROC_INST_ID_ = '4625114'
order by
RES.ID_ asc
limit 2147483647 OFFSET 0
- 工作流新增页面去掉提交按钮
onAfterQuery(type, isSuccess, result) {
if (result && isSuccess) {
if(this.vm.action === 'processStart' || result.models.model.status>=3){
this.vm.$refs.qmWorkflow.$refs.processSendBtn.$el.style.display = 'none'
}
}
return super.onAfterQuery(type, isSuccess, result);
}
- 前端注意是否少冒号
key-prop="opportunityId" //没有冒号
:rules="rules"//加<el-form 内>
- 在这里获取后台工作流传过来的值,再传给create页面
onAfterGetEntity(result) {
result.controlData.departmentList = this.vm.list;
if (result.models.model.departmentId != null) {
result.models.model.departmentId = Number(
result.models.model.departmentId
);
}
result.controlData.opportunityAuditResultEnum = this.vm.list;
}
- vue需要传的组件id
props: {
custPageAction: String,
action: String,
taskId: String,
historyTaskId: String,
assigneeId: String,
version: String,
},
- 当前端工作流,点击任何按钮都没有提示也没有报错的时候,注意查看APPcode是否有写,还有加上弹窗层,因为这里面需要传值
<vxe-modal v-model="createVisiable" width="80%" height="800" :title="modalTitle" :show-footer="false"
:show-zoom="true"
:resize="true"
:transfer="true"
:destroy-on-close="true"
>
<template #default>
<Create
ref="Create"
:action="action"
:taskId="action === 'processEdit' ? taskId : ''"
:historyTaskId="action === 'processView' ? historyTaskId : ''"
:assigneeId="action === 'processEdit' ? assigneeId : ''"
:version="version"
:custPageAction="custPageAction"
></Create>
</template>
</vxe-modal>
- 后台报控制错误,点击查看和编辑报无法找到实体组件,证明没有传到对应的编辑 按钮值到后台(我这次的主要问题是自己主键id没传,直接复制了其他的工作流没改)
processOn(row, viewPageAction) {
this.getWorkflowArgs({formId: row.riskId}).then((rlt) => {
//打开页面清理缓存
this.action = '';
this.taskId = '';
this.assigneeId = '';
this.historyTaskId = '';
this.version = '';
//由于此处采用的对话框方式打开,所以是选择参数往对话框传递,不采用拼接url打开新窗口的方式
if (rlt.taskId && viewPageAction == 'edit') {
this.action = 'processEdit';
this.taskId = rlt.taskId;
this.assigneeId = rlt.assigneeId;
this.version = rlt.version;
this.custPageAction = 'edit';
this.modalTitle = "办理机遇";
} else if (rlt.historyTaskId || viewPageAction == 'view') {
this.action = 'processView';
this.historyTaskId = rlt.historyTaskId ? rlt.historyTaskId : rlt.taskId;
this.version = rlt.version;
this.custPageAction = 'view';
this.modalTitle = "查看风险";
}
if (viewPageAction) {
this.custPageAction = viewPageAction;
}
this.createVisiable = true;
});
},
- 后台报错没有指定参与者,是因为重新部署工作流的时候,没有设置参与者
- isLastTask,最后环节,刷新当前状态
- 工作流传阅
public void send(){
WorkflowContext context = getWorkflowContext();
TrainPlan formData = (TrainPlan) context.getFormData();
//给所有的授课负责人发送待阅信息
List<TrainPlanDetail> train = trainPlanDetailService.list(new QueryWrapper<TrainPlanDetail>().eq("plan_id", formData.getPlanId()));
String userIds = train.stream().filter(tran -> tran.getPrincipalUserId()!=null)
.map(TrainPlanDetail::getPrincipalUserId)
.collect(Collectors.joining(","));
//给所有培训科室发
List<Long> planDetailIds = train.stream().map(TrainPlanDetail::getPlanDetailId).collect(Collectors.toList());
QueryWrapper<TaskDepartment> qw =new QueryWrapper<>();
qw.in("task_id", planDetailIds);
qw.eq("type", BusinessDepartmentTypeEnum.INTERNAL_TRAIN.getValue());
List<TaskDepartment> departmentList = taskDepartmentService.list(qw);
List<String> collect = departmentList.stream().map(TaskDepartment::getDepartmentId).collect(Collectors.toList());
//去重
List<String> departmentIds = new ArrayList<String>(new TreeSet<String>(collect));
//遍历所有的部门
for (String departmentId:departmentIds) {
List<String> departmentManagerLoginIds = iSysUserService.getDepartmentManagerLoginIds(departmentId);
for (String loginId:departmentManagerLoginIds) {
SysUser byId = iSysUserService.getByLoginId(loginId);
userIds=userIds+","+byId.getUserId();
}
}
if(!StringUtils.isEmpty(userIds)){
actExtWorkItemService.processDoNotify(context.getWorkflowTaskContext().getTaskId(),userIds);
}
}
- boolean isLastTask:当前工作流是否全部完成
vue
-
vue定义值,let status即可
-
根据状态判断是否显示
:menuFunc="{
remove: (row) => row.workStatus == 1,
}"
- request没定义,需要引入或者直接this.request
-
async:异步 await
if (
this.controlData.workflow.taskCode &&
this.controlData.workflow.taskCode === "usertask4"
) {
//发起步骤检查校准核查记录是否有数据
const srmInspectionDetail =
this.$refs["srmInspectionDetail"].query.data;
const idList = srmInspectionDetail.map(
(v) => v.inspectionDetailId
);
const res = await this.request.postJson(
"/lab/srmInspection/selectSrmInspectionDetail",
idList
);
if (res) {
let seqList = [];
for (let i = 0; i < res.length; i++) {
let p = res[i];
if (p.flag === 0) {
seqList.push(i + 1);
}
}
if (seqList.length > 0) {
this.$message.error(
"序号为" +
seqList.join(",") +
"的校准明细没有添加核查记录,请检查!"
);
return;
}
}
js
import request from "@/utils/request";
this.request
-
传参
-
vue删除数据
<template v-slot:moreBtn="{ row }">
<el-button type="text" @click="processOn(row, 'view')">查看</el-button>
<el-button type="text" v-if="row.status == 0" @click="processOn(row, 'edit')">编辑</el-button>
<el-link type="danger" v-if="row.status == 0" @click="removeNewFunc(row)">删除</el-link>
</template>
async removeNewFunc(row) {
const res = await request({
url: "/lab/equipmentPeriodPlan/query",
data: {
start: 0,
length: 999,
draw: 1,
query: {
planId: row.planId,
},
},
method: "post",
});
let list = res.data;
let isAll;
if (list.length > 0) {
isAll = list.every((item) => {
return item.status == 0;
});
} else {
isAll = true;
}
if (!isAll) {
this.$message.error("已流转的计划信息不可删除");
return;
}
let deleteList = [];
const type = await this.$confirm(
"此操作将删除该数据(注:只删除未经流转的仪器设备期间核查计划信息), 确定继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
closeOnClickModal: false,
}
);
if (type === "confirm") {
deleteList.push(row.planId);
request
.postJson("/lab/equipmentPeriodPlan/remove", deleteList)
.then((resp) => {
if (resp.success) {
this.$message.success("删除成功");
this.searchQuery();
} else {
this.$message.error(resp.message);
}
});
}
},
- 是否显示页面
:show-view="status < 3"
- 删除按钮
:menuFunc="{ remove: (row) => row.status == 0 }"
- 前端vue根据单价数量自动算出总价
<el-col :span="12">
<el-form-item label="数量" prop="model.number">
<el-input
v-model="models.model.number"
oninput="value=value.replace(/[^\d]/g,'')"
:min="0"
placeholder="请输入"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="单价(元)" prop="model.unitPrice">
<el-input
v-model.number="models.model.unitPrice"
type="number"
:min="0"
placeholder="请输入"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="总价" prop="model.totalPrice">
<el-input
v-model="models.model.totalPrice"
disabled
placeholder="自动计算"
></el-input>
</el-form-item>
</el-col>
</el-row>
watch: {
"models.model.number": function (val) {
if(this.models.model.number && this.models.model.unitPrice ){
let x1 = new BigNumber(this.models.model.number)
let x2 = new BigNumber(this.models.model.unitPrice)
let y = x1.multipliedBy(x2)
this.models.model.totalPrice = y.toNumber()
}else{
this.models.model.totalPrice = 0
}
},
"models.model.unitPrice": function (val) {
if(this.models.model.number && this.models.model.unitPrice ){
let x1 = new BigNumber(this.models.model.number)
let x2 = new BigNumber(this.models.model.unitPrice)
let y = x1.multipliedBy(x2)
this.models.model.totalPrice = y.toNumber()
}else{
this.models.model.totalPrice = 0
}
},
},
- rules验证,要用prop绑定属性
prop="model.supervisionContent"
- vue前端不同页面传值
- 在对应的list页面获取到要传的值,绑定到v-bind
<el-form>
<recordList
v-bind="{ name, unit,trainAddress,planDetailId,planStartDate, status, customizePageAction }"
>
</recordList>
</el-form>
//绑定跳到对应页面
import recordList from "@/views/lab/trainManagement/internalTraining/record/list";
- 在data里面定义要传的值
data() {
return {
util: Util,
recordListModalVisiable: false,
planDetailId: "",
name: "",
unit: "",
trainAddress: "",
planStartDate: "",
planEndDate: "",
};
},
- 写对应的行方法获取到他们的值
showRecordList(row) {
this.planDetailId = row.planDetailId;
this.name = row.name;
this.unit = row.unit;
this.trainAddress = row.trainAddress;
this.planStartDate = row.planStartDate;
this.planEndDate = row.planEndDate;
this.recordListModalVisiable = true;
},
- 在接收数据页面,接收值
//给页面初始化的时候赋值
onAfterGetEntity(result) {
result.models.model.instructor = this.vm.name;
result.models.model.instructorUnit = this.vm.unit;
result.models.model.trainingPlace = this.vm.trainAddress;
result.models.model.planStartDate = this.vm.planStartDate;
result.models.model.planEndDate = this.vm.planEndDate;
}
//先定义接收值的类型
props: {
planDetailId: String,
status: Number,
customizePageAction: String,
name: String,
unit: String,
trainAddress: String,
planStartDate: String,
planEndDate: String,
},
- 页面传值
<div>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>申购明细</span>
</div>
<div>
<el-form>
<srmPurchaseDetail
ref="srmPurchaseDetail"
@updatesumPrice="updatesumPrice"
v-bind="{
purchasePlanId: models.model.purchasePlanId,
status: models.model.status,
action: action,
controlDataA: controlData,
}"
></srmPurchaseDetail>
</el-form>
</div>
</el-card>
</div>
//对应页面接收值
props:{
purchasePlanId: String,
action: String,
status: Number,
controlDataA: Object
},
- 公司框架自带传值
:model-data="{status}"//从list传到create(定义一个对象大括号)
props: {//对应页面定义接收值
modelData:Object,
models: Object,
controlData: Object,
pageAction: String
},
- vue传值,这里里面传值通过路径跳转传到其他页面
- 前端类型转换,转成number
Number(this.models.model.status)
- vue调用方法请求放在methods里面
- vue,前端格式化时间传到后台
:value-format="yyyy-MM-dd"
- 根据状态判断是否显示按钮
//培训人员
String trainUserIds = externalTrainUserService.getBaseMapper()
.selectList(new QueryWrapper<ExternalTrainUser>()
.lambda()
.eq(ExternalTrainUser::getTrainId,entity.getTrainId())
.eq(ExternalTrainUser::getUserType,byValue))
.stream()
.map(ExternalTrainUser::getUserId)
.collect(Collectors.joining(","));
entity.setTrainUser(StringUtils.isEmpty(trainUserIds) ? "" : trainUserIds);
entity.setTrainUserIds(StringUtils.isEmpty(trainUserIds) ? new ArrayList<>() : Arrays.asList(trainUserIds.split(",")));
users = sysUserService.lambdaQuery().in(SysUser::getUserId, equipmentVerificationCalibrationService
.list(new QueryWrapper<EquipmentVerificationCalibration>().eq("plan_id", formData.getPlanId()))
.stream().map(EquipmentVerificationCalibration::getEquipmentCustodianId).distinct().collect(Collectors.toList())).list()//这里查的是仪器设备检定/校准表 设备保管人主键id
.stream().map(SysUser::getLoginId).collect(Collectors.toList());
- vue页面传值
<el-card class="box-card">
<div slot="header" class="clearfix"><span></span></div>
<el-form>
<Record ref="record"
:planId="models.model.planId ? models.model.planId.toString() : ''"
:status="models.model.status"
:workflowArgs="controlData.workflow"
:cuPageAction="pageAction"
></Record>
</el-form>
</el-card>
onBeforeSave(postModel) {
var recordList = this.vm.$refs.record.query.data
if(postModel.model.status==3){
for (var i=0;i< recordList.length;i++){
if(!recordList[i].noteTakerId){
this.vm.$message.warning('请输入编写确认记录员!')
return false
}
}
}
let json3 = JSON.stringify(recordList);
postModel.recordList = json3;
}
-
opportunityAuditResultEnum//机遇审核结果
- if判断
if判断: v-if="models.model.basis!=null && models.model.basis.indexOf(4)!=-1 "
:disabled="models.model.status != 3 || custPageAction == 'view'"
找到其父组件判断是否显示按钮: :show-edit="taskCode!='usertask5'"(思路:可以先塞值(true,false)判断是否生效,再真实传值)
- 引入函数正则表达式
"model.phone": pattern.telephone(),
- 显示最大输入字符
maxlength="50"
show-word-limit
- 刷新当前页面
普通刷新当前页面
this.$refs.qmTable.refresh();
工作流新增数据刷新
qmWorkflowDone() {
if (this.isList) {
this.$parent.$emit('input', false)
this.$parent.$parent.$refs.qmTable.refresh()
} else {
this.$parent.close()
this.$parent.$parent.close()
}
}
- 注意显示列表数据,注意其属性
fieldtype: 这个是他的类型,用不到可以直接去掉
- 下拉框select:
v-model
的值为当前被选中的el-option
的 value 属性值
:value="item.key",这个是显示下拉框的值
- 因为在el-from里面套多了一层导致rules不生效,去掉el-from即可
- :disabled:“大概意思是disabled接受的属性是一个布尔值,但是这个布尔值为true是不能直接在标签内改的。”
- 是否显示按钮
computed:{
showButton(){
if(this.status === 3 && this.customizePageAction === 'edit'){
return true;
}else{
return false;
}
}
},
:show-add="showButton"
:show-edit="showButton"
:show-delete="showButton"
- 绑定当前属性:prop=“model.external”
elementUi
- element前端时间搜索框
<el-col :span="6">
<el-form-item label="发出时间:">
<el-date-picker
v-model="search.startTime"
type="date"
placeholder="请选择发出时间"
>
</el-date-picker>
</el-form-item>
</el-col>
- 设置全局样式
:form-option="{labelWidth: '180px',labelSuffix:':'}"
- 前端类型转换
.map(Number)
:key="Number(item.value)
- bigint对应的是long类型
<el-col :span="12">
<el-form-item label="开箱时间:" prop="model.unpackTime">
<el-date-picker
v-model="models.model.unpackTime"
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
</el-col>
created() {
if(!this.models.model.unpackTime){
this.$set(this.models.model,'unpackTime',this.getNowTime())
}
},
methods: {
getNowTime() {
var now = new Date();
var year = now.getFullYear(); //得到年份
var month = now.getMonth() + 1; //得到月份
var date = now.getDate(); //得到日期
month = month.toString().padStart(2, "0");
date = date.toString().padStart(2, "0");
var defaultDate = `${year}-${month}-${date}`;
return defaultDate
},
}
- 样式
尾缀:label-suffix=":"
宽度:label-width="140px"谨记要加px
- :showOrder=“true” ,默认排序
- 下拉框多选属性:multiple
- 时间输入框限制
<el-row>
<el-col :span="12">
<el-form-item label="预计培训开始日期:" prop="model.planStartDate">
<el-date-picker
v-model="models.model.planStartDate"
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
placeholder="请选择预计培训开始日期"
:picker-options="{disabledDate: data => models.model.planEndDate?data > new Date(models.model.planEndDate):false}"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预计培训结束日期:" prop="model.planEndDate">
<el-date-picker
v-model="models.model.planEndDate"
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
placeholder="请选择预计培训结束日期"
:picker-options="{disabledDate: data => models.model.planStartDate?data < new Date(models.model.planStartDate):false}"
>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
- 直接通過v-if判断是否显示按钮(row可以直接获取按钮里面的值)
<template v-slot:moreBtn="{ row }">
<el-button type="text" @click="processOn(row, 'view')">查看</el-button>
<el-button type="text" v-if="row.status ==0" @click="processOn(row, 'edit')">编辑</el-button>
<el-link type="danger" v-if="row.status ==0" @click="removeNewFunc(row)">删除</el-link>
</template>
mybatis-plus+stream
- list根据字段去重
//根据值班日期去重,一天只需要获取一条数据
List<SiteScheduling> siteSchedulings = schedulingList.stream()
.collect(Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(SiteScheduling::getOnDutyDate))), ArrayList::new));
- 删除
@PostMapping("/remove")
public Result remove(@RequestBody ArrayList<Long> ids) {
baseService.lambdaUpdate().set(Sample::getIsDeleted, true)
.in(Sample::getSampleId, ids).update();
//更新任务明细情况
taskDetailService.lambdaUpdate()
.set(TaskDetail::getSampleId, null)
.set(TaskDetail::getSampleCode, null)
.set(TaskDetail::getSampleStatus, TaskDetailProcessEnum.Untreated.getValue())
.in(TaskDetail::getSampleId, ids).update();
baseService.deleteProcess(ids);
return Result.ok();
}
- mybatisplus构造器,条件删除数据
if (id !=null) {
QueryWrapper<ActExtWorkInst> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("FORM_ID", id);
iActExtWorkInstService.remove(queryWrapper);
}
- mybatisplus构造器:
QueryWrapper<Sample> qw = new QueryWrapper<>();
qw.in("sample_id", sampleList);
List<Sample> samples = baseService.getBaseMapper().selectList(qw);
- mybatis-plus 构造条件删除方法
QueryWrapper<ActExtWorkInst> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("FORM_ID", id);
iActExtWorkInstService.remove(queryWrapper);
- 数组转list
List<String> userIds = Arrays.asList(split);
//返回项目组员loginId
String collect = iSysUserService.lambdaQuery()
.in(SysUser::getUserId, userIds)
.list().stream().map(SysUser::getUserName)
.collect(Collectors.joining(","));
-
命名空间指到对应的文件
-
mybatisplus :内置 Sql 注入剥离器,有效预防Sql注入攻击 。
-
不加条件就是查询全部
baseService.lambdaQuery().select().list();
- stream对list多个字段进行判断分组, groupingBy 进行多字段分组
Map<String,List<ApplySampleAndTaskDetailVO>> pointTaskDetailsMap = pointTaskDetails.stream()
.collect(Collectors.groupingBy(a->a.getSampleTypeName()+"_"+a.getObjectName()+"_"+a.getSampleDeadline()+"_"+a.getSampleTypeName()));
- mybatisplus的修改方法lambdaQuery()
List<TaskDetail> taskDetails = iTaskDetailService.lambdaQuery().eq(TaskDetail::getTaskId, formData.getTaskId()).list();
if (!CollectionUtils.isEmpty(taskDetails)){
for (TaskDetail taskDetail : taskDetails) {
boolean b = iTaskDetailService.lambdaUpdate().set(TaskDetail::getIsDeleted,1)
.eq(TaskDetail::getTaskDetailId, taskDetail.getTaskDetailId()).update();
}
}
- 转成map方便前段取值
Map<String, Sample> sampleCodeMap = list.stream().collect(Collectors.toMap(Sample::getSampleCode, sample -> sample));
-
Collectors.toMap()
-
想获得一个id和name对应的Map<String, String> :
Map<String, String> map = list.stream().collect(Collectors.toMap(Student::getId,Student::getName));
注意:name可以为空字符串但不能为null,否则会报空指针,解决方案:
Map<String, String> map = list.stream().collect(Collectors.toMap(Student::getId, e->e.getName()==null?“”:e.getName()));
-
mybatisplus查询多个
LambdaQueryChainWrapper<Spot> w = iSpotService.lambdaQuery().select(Spot::getSpotId,Spot::getName);
- mybatisplus查询时间区间内的数据
List<Task> taskList = baseMapper.selectList(new QueryWrapper<Task>().lambda()
.ge(StringUtils.hasText(startTime), Task::getCreateTime, startTime)
.le(StringUtils.hasText(endTime), Task::getCreateTime, endTime));
- 限定数据条数
List<Task> taskList = baseService.lambdaQuery().eq(Task::getTaskType,TaskTypeEnum.NATIONAL_CONTROL_POINT_MONITORING_TASK_LIST.getValue())
.eq(Task::getIsDeleted,0)
.last("limit "+num).list();
- 查询stream map过滤字段,查询返回某个字段
List<String> documentName = baseService.lambdaQuery().lt(NormativeDocument::getDocumentId, 600).list().stream()
.map(NormativeDocument::getDocumentName).distinct().collect(Collectors.toList());
- mybatisPlus修改数据update
lambdaUpdate().set(SysUser::getPassword,SecureUtils.getMD5(newPassword)).eq(SysUser::getUserId,userId).update();
- mybatispuls根据多个id查询数据
List<SrmPurchaseDetail> srmPurchaseDetailList = baseService.lambdaQuery().in(SrmPurchaseDetail::getPurchaseDetailId, idList).list();
- mybatispuls排序
List<SrmPurchaseDetail> srmPurchaseDetailList = baseService.lambdaQuery().in(SrmPurchaseDetail::getPurchaseDetailId, idList).orderByDesc(SrmPurchaseDetail::getCreateTime).list();
- 查询仪器名称(stream),分页返回十条数据
//查询仪器名称
@ResponseBody
@RequestMapping("getEquipmentName")
public Map<String,String> getEquipmentName(){
Page<EquipmentManage> page = baseService.lambdaQuery().select(EquipmentManage::getEquipmentId,EquipmentManage::getEquipmentName).page(new Page(1, 10));
Map<String, String> collect = page.getRecords().stream().collect(Collectors.toMap(v -> v.getEquipmentId().toString(), EquipmentManage::getEquipmentName));
return collect;
- mybatisplus模糊查询,分页
//查询仪器名称
@ResponseBody
@RequestMapping("getEquipmentName")
public Map<String,Map<String,Object>> getEquipmentName(String id,String name){
LambdaQueryChainWrapper<EquipmentManage> w = baseService.lambdaQuery().select(EquipmentManage::getEquipmentId, EquipmentManage::getEquipmentName,EquipmentManage::getEquipmentCode);
if (StringUtils.hasText(id)){
w.eq(EquipmentManage::getEquipmentId,id);
}else if (StringUtils.hasText(name)){
w.like(EquipmentManage::getEquipmentName,name);
}
w.eq(EquipmentManage::getIsDeleted,false);
Page<EquipmentManage> page = w.page(new Page(1, 10));
Map<String, Map<String,Object>> collect = page.getRecords().stream().collect(Collectors.toMap(v -> v.getEquipmentId().toString(), v->{
Map<String,Object> result = new HashMap<>();
result.put("equipmentName", v.getEquipmentName());
result.put("equipmentCode", v.getEquipmentCode());
return result;
}));
return collect;
}
-
mybatisplus条件拼接
-
通stream多次map类型转换获取对应的值
public List<String> getUserLoginIdList(Long planDetailId, Integer userType) {
return iSysUserService.lambdaQuery().in(SysUser::getUserId, iStaffSupervisionStaffService.
list(new QueryWrapper<StaffSupervisionStaff>().eq("plan_detail_id", planDetailId).eq("user_type", userType))
.stream().map(StaffSupervisionStaff::getUserId).collect(Collectors.toList())).list()
.stream().map(SysUser::getLoginId).collect(Collectors.toList());
}
- 根据id查询某一个字段的所有值
List<String> userLoginIdList = externalTrainUserService.list(new QueryWrapper<ExternalTrainUser>()
.eq("train_id", formData.getTrainId()))
.stream()
.map(ExternalTrainUser::getLoginId)
.collect(Collectors.toList());
- mybatisplus+stream
//培训人员
String trainUserIds = externalTrainUserService.getBaseMapper()
.selectList(new QueryWrapper<ExternalTrainUser>()
.lambda()
.eq(ExternalTrainUser::getTrainId,entity.getTrainId())
.eq(ExternalTrainUser::getUserType,byValue))
.stream()
.map(ExternalTrainUser::getUserId)
.collect(Collectors.joining(","));
entity.setTrainUser(StringUtils.isEmpty(trainUserIds) ? "" : trainUserIds);
entity.setTrainUserIds(StringUtils.isEmpty(trainUserIds) ? new ArrayList<>() : Arrays.asList(trainUserIds.split(",")));
users = sysUserService.lambdaQuery().in(SysUser::getUserId, equipmentVerificationCalibrationService
.list(new QueryWrapper<EquipmentVerificationCalibration>().eq("plan_id", formData.getPlanId()))
.stream().map(EquipmentVerificationCalibration::getEquipmentCustodianId).distinct().collect(Collectors.toList())).list()//这里查的是仪器设备检定/校准表 设备保管人主键id
.stream().map(SysUser::getLoginId).collect(Collectors.toList());
users = sysUserService.lambdaQuery().in(SysUser::getUserId, equipmentVerificationCalibrationService
.list(new QueryWrapper<EquipmentVerificationCalibration>().eq("plan_id", formData.getPlanId()))
.stream().map(EquipmentVerificationCalibration::getEquipmentCustodianId).distinct().collect(Collectors.toList())).list()//这里查的是仪器设备检定/校准表 设备保管人主键id
.stream().map(SysUser::getLoginId).collect(Collectors.toList());
- lambda+mybatispuls
users = sysUserService.lambdaQuery().in(SysUser::getUserId,
equipmentVerificationCalibrationService.list(new QueryWrapper<EquipmentVerificationCalibration>()
.eq("plan_id", formData.getPlanId()))
.stream().map(EquipmentVerificationCalibration::getEquipmentManagerId).distinct().collect(Collectors.toList())).list()
.stream().map(SysUser::getLoginId).collect(Collectors.toList());
- @TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。
- 根据当前主键id,查询所有清单id
List<StaffSupervisionPlanDetail> planDetailIds = iStaffSupervisionPlanDetailService.listPlanDetailByPlanIds(entity.getPlanId());
BusinessDepartment businessDepartment = iBusinessDepartmentService.getEntityByName(cell0.getStringCellValue());
BusinessDepartment getEntityByName(String stringCellValue);
@Override
public BusinessDepartment getEntityByName(String stringCellValue) {
return this.lambdaQuery().eq(BusinessDepartment::getDepartmentName,stringCellValue)
.orderByDesc(BusinessDepartment::getCreateTime)
.last("limit 1")
.one();
}
-
- 通过id获取数据
List<TrainRecordDetailed> trainRecordDetailedList = trainRecordDetailedService.lambdaQuery().eq(TrainRecordDetailed::getRecordId, recordId).list();
自己写sql
@Override
public StaffSupervisionStaff getInfoByPlanDetailId(String planId,Integer userType) {
return baseMapper.getInfoByPlanDetailId(planId,userType);
}
根据名称查询当前表的所有数据
List<Supplier> suppliers = this.baseService.lambdaQuery().eq(Supplier::getSupplierName,entity.getSupplierName()).list();
根据list返回数据,获取指定的字段(stream过滤数据)
@Override
public List<String> getUserId(String s) {
return (List<String>) this.lambdaQuery().in(SysUser::getUserName,"黄苑军,吴依妮,廖柳凤")//改变返回类型
.list()
.stream().map(SysUser::getUserName).collect(Collectors.toList());
}
如果有一样的数据,就塞在同一行里
<select id="getInfoByPlanDetailId" resultType="com.qm.boot.web.business.lab.entity.StaffSupervisionStaff">
select GROUP_CONCAT( DISTINCT a.user_name) as userNames from staff_supervision_staff a
<if test="search.userType != null">
and a.user_type=#{userType}
</if>
<if test="search.planDetailId != null">
and a.plan_detail_id=#{planDetailId}
</if>
</select>
- mybatis-puls简写
externalTrainUserService.remove(new QueryWrapper<ExternalTrainUser>().eq("train_id", formData.getTrainId()));
mysql
- 转义
<![CDATA[ <= ]]>
- mybatis实体查询参数
<if test="siteOnDutyManagementProblem.timeInterval != null">
and sodmp.time_interval =
#{siteOnDutyManagementProblem.timeInterval}
</if>
- mysql判空
and
(s.is_deleted = '0' or s.is_deleted is null)
- ""双引号里面加’'单引号
<if test="samplePrintStatus != null">
<choose>
<when test="samplePrintStatus == '未打印' or samplePrintStatus == '已打印'" >
and s.sample_print_status = #{samplePrintStatus}
</when>
<otherwise>
and s.sample_id = #{samplePrintStatus}
</otherwise>
</choose>
</if>
- m ybatis截串(值需要是数组类型) 数据截串查询
<if test="spotName != null and spotName != ''">
and td.spot_name in
<foreach collection="spotName" item="spotName" index="index" open="(" close=")" separator=",">
#{spotName}
</foreach>
</if>
- 时间区间查询
<if test="startDate!=null and startDate!=''and endDate!=null and endDate!=''">
and a.createTime between #{startDate} and #{endDate}
</if>
- 模糊查询
<if test="task != null">
AND (td.object_name LIKE concat('%',#{task},'%')
OR td.spot_name LIKE concat('%',#{task},'%')
OR td.sample_code LIKE concat('%',#{task},'%'))
</if>
- join默认使用最小的表作为主表最好用left join
- order by 多个字段排序
order by
d.assignee_time desc,d.work_assignee_time desc
- union:查询得字段要一直,没有的话就默认赋值为空""
- select count(1) 查询有多少条符合条件的数据
- alt+x执行多条语句
- mysql的 union all 不会去掉重复数据 和 union(一般都是用union)去掉重复数据
select a.*
from (
select
distinct inst.INSTANCE_TITLE instance_title,
t.task_id,
t.project_name,
t.project_code,
t.task_type,
t.task_code,
t.task_user_name,
t.task_user_id,
t.task_time,
t.finish_time,
t.create_time
from
task t
left join act_ext_work_inst inst on
t.task_id = inst.FORM_ID
left join detect_record dr on dr.detect_record_id = inst.FORM_ID
join act_ext_app aea on
inst.DEFINITION_ID = aea.DEFINITION_ID
join act_ext_work_item item on
inst.INSTANCE_ID = item.INSTANCE_ID
where 1=1
and item.TASK_STATUS = 'processing'
and item.ASSIGNEE_ID = '1513773965552762882'
and t.task_type = '4'
and inst.APP_CODE = 'MultipleTask'
and t.is_deleted = 0
union all
select
distinct inst.INSTANCE_TITLE instance_title,
t.task_id,
t.project_name,
t.project_code,
t.task_type,
t.task_code,
t.task_user_name,
t.task_user_id,
t.task_time,
t.finish_time,
t.create_time
from
task t
left join task_detail td on td.task_id = t.task_id
left join detect_record dr on dr.task_detail_id = td.task_detail_id
left join act_ext_work_inst inst on dr.detect_record_id = inst.FORM_ID
join act_ext_work_item item on
inst.INSTANCE_ID = item.INSTANCE_ID
where 1=1
and item.TASK_STATUS = 'processing'
and item.ASSIGNEE_ID = '1513773965552762882'
and t.task_type = '4'
and inst.APP_CODE = 'labMeasure'
and t.is_deleted = 0
) a ```
- **InnoDB支持事务,MyISAM不支持**,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
- InnoDB支持外键,MyISAM不支持
- 从MySQL5.5.5以后,InnoDB是默认引擎
- 子查询
```sql
# 查询工资大于149号员工工资的员工的信息
SELECT employee_id,last_name,salary
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE employee_id=149);
# 返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
SELECT last_name,job_id,salary
FROM employees
WHERE job_id=(
SELECT job_id
FROM employees
WHERE employee_id=141)
AND salary>(
SELECT salary
FROM employees
WHERE employee_id=143);
# 返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
SELECT MIN(salary)
FROM employees);
#2.查询工资比公司平均工资高的员工的员工号,姓名和工资。
SELECT employee_id,last_name,salary
FROM employees
WHERE salary > (
SELECT AVG(salary)
FROM employees
);
#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
SELECT employee_id,last_name
FROM employees
WHERE department_id IN (
SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE '%u%'
);
# 查询与141号员工的manager_id和department_id相同的其他员工
# 法一:(正常思路)
SELECT employee_id,manager_id,department_id
FROM employees
WHERE manager_id=(
SELECT manager_id
FROM employees
WHERE employee_id=141)
AND department_id=(
SELECT department_id
FROM employees
WHERE employee_id=141)
AND employee_id<>141;# 注意去除141号员工本身
# 法二:
SELECT employee_id,manager_id,department_id
FROM employees
WHERE (manager_id,department_id)=(
SELECT manager_id,department_id
FROM employees
WHERE employee_id=141)
AND employee_id<>141;# 注意去除141号员工本身
- MySQL事务
- MySQL中服务器层不管理事务,事务是由存储引擎实现的。**MySQL支持事务的存储引擎有InnoDB、NDB Cluster等,其中InnoDB的使用最为广泛;其他存储引擎不支持事务,如MyIsam、Memory等
ACID特性
ACID是衡量事务的四个特性:
- 原子性(Atomicity,或称不可分割性)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
- mysql动态sql
select
*
from
task_detail td
left join task t on
t.task_id = td.task_id
<where>
td.task_id = #{taskId}
and
t.task_type = #{taskType}
and
td.is_deleted = '0'
<choose>
<when test="isAudit == 0">
and td.detect_status in (1,2,3)
</when>
<otherwise>
and td.detect_status = #{isAudit}
</otherwise>
</choose>
</where>
update equipment set a = b 就是了
lambda表达式
- lambda模糊查询
public PagerInfo<Apply> getPage(Apply e, String startApplyTime, String endApplyTime, Boolean fromPortal) {
PagerInfo<Apply> pagerInfo = new PagerInfo<>();
ListQueryParser parser = new ListQueryParser(request);
LambdaQueryWrapper<Apply> qw = new QueryWrapper<Apply>().lambda();
pagerInfo.setOrigin(parser);
pagerInfo.setDraw(parser.getDraw());
pagerInfo.setCurrent(parser.getStartPage());
pagerInfo.setSize(parser.getPageSize());
String createUserId = e.getCreateUserId();
if (StringUtils.hasText(createUserId)) {
qw.eq(Apply::getCreateUserId, createUserId);
}
Integer applyType = e.getApplyType();
if (applyType != null) {
qw.eq(Apply::getApplyType, applyType);
}
String applyCode = e.getApplyCode();
if (StringUtils.hasText(applyCode)) {
qw.like(Apply::getApplyCode, applyCode);
}
String enterpriseName = e.getEnterpriseName();
if (StringUtils.hasText(enterpriseName)) {
qw.like(Apply::getEnterpriseName, enterpriseName);
}
boolean isStartApplyTime = StringUtils.hasText(startApplyTime);
boolean isEndApplyTime = StringUtils.hasText(endApplyTime);
if (isEndApplyTime) {
endApplyTime += " 23:59:59";
}
if (isStartApplyTime && isEndApplyTime) {
qw.between(Apply::getApplyTime, startApplyTime, endApplyTime);
} else if (isStartApplyTime) {
qw.ge(Apply::getApplyTime, startApplyTime);
} else if (isEndApplyTime) {
qw.le(Apply::getApplyTime, endApplyTime);
}
qw.eq(Apply::getIsDeleted, false);
if (fromPortal == null || !fromPortal) {
qw.ne(Apply::getAcceptStatus, 0);
}else{
Integer acceptStatus = e.getAcceptStatus();
if (acceptStatus!=null) {
qw.eq(Apply::getAcceptStatus,acceptStatus);
}
}
qw.orderByDesc(Apply::getCreateTime);
// 让数据权限生效
String dataExpr = QueryHelper.getParsedDataExpression(request, null);
if (!org.apache.commons.lang3.StringUtils.isEmpty(dataExpr)) {
qw.apply(dataExpr);
parser.addDataExpression(dataExpr);
}
return baseService.page(pagerInfo, qw);
}
List<String> sampleDeptIds = list.stream().map(m -> m.getSampleDeptId()).collect(Collectors.toList());
- lambda
if(null == theItem){
theItem = items.stream().filter(a -> {
return Framework.getCurrentUser().getUserId().equalsIgnoreCase(a.getAssigneeId());
}).findFirst().orElse(null);
}
- lambda表达实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
方法引用:类名::方法
Map
- mybatis参数需要多个的时候,可以用map封装到后台查
Map<String,Object> params = new HashMap<>();
数据结构
- 创建一个ArrayList对象
List<String> names1 = new ArrayList<String>();
- 数据结构:
- 数组结构(大小固定不易动态扩展,查读容易,增删难)
- 链表结构(插入删除速度快,内存利用率高,没有固定大小,扩展灵活,查找慢)
- 哈希表结构(结合数组结构和链表结构的优点,从而实现了查询和修改效率高,插入和删除效率也高的一种数据结构
常见的HashMap就是这样的一种数据结构)
- hashcode:hashcode就是一个签名。当两个对象的hashcode一样时,两个对象就有可能一样。如果不一样的话两个对象就肯定不一样
类型转换
- string转list
List<String> loginId = Arrays.asList(context.getCurrentWorkflowUser().getLoginId());
- 数据转换类型(转成实体)
EquipmentPurchase formData = (EquipmentPurchase) context.getFormData();
- 数组转list
String[] strArray = { "a", "b" };
List<String> strList = Arrays.asList(strArray);
- 把对象转成map
Map<String, Object> dataMap = MapUtil.toMap(vo);
代码优化
- 减少循环次数,最简单的办法是,把第二层循环的集合变成
map
,这样可以直接通过key
,获取想要的value
数据。
原代码
for(User user: userList) {
for(Role role: roleList) {
if(user.getRoleId().equals(role.getId())) {
user.setRoleName(role.getName());
}
}
}
优化后
Map<Long, List<Role>> roleMap = roleList.stream().collect(Collectors.groupingBy(Role::getId));
for (User user : userList) {
List<Role> roles = roleMap.get(user.getRoleId());
if(CollectionUtils.isNotEmpty(roles)) {
user.setRoleName(roles.get(0).getName());
}
}
-
优化后性能提升了一倍,嵌套循环应该遵循“外小内大”的原则,这就好比你复制很多个小文件和复制几个大文件的区别。
-
提取与循环无关的表达式
-
list.size()每次循环都会被执行一次,这无疑会影响程序的性能,所以应该将其放到循环外面,用一个变量来代替,优化前后的对比也很明显。
-
大家都知道,捕获异常是很耗资源的,所以不要讲try catch放到循环内部,优化后同样有好几个数量级的提升。
前
stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
try {
} catch (Exception e) {
}
}
endTime = System.nanoTime();
System.out.println("在内部捕获异常耗时:"+(endTime - stratTime));
后
stratTime = System.nanoTime();
try {
for (int i = 0; i < 10000000; i++) {
}
} catch (Exception e) {
}
endTime = System.nanoTime();
System.out.println("在外部捕获异常耗时:"+(endTime - stratTime));
注意事项
- 出问题记得debug,注意上下文的代码逻辑,下面debug进不去可能在上一步就已经跑完
- 判空类型不一致会报错
- 联表查不出数据的时候,注意查看关联条件(有可能关联的id空了)
- 注意查看报错信息上下文
- 注意:判断进不去,是否有加冒号或者其他标点符号导致不相等equals
- 注意for循环的时候,数据体放在循环里还是循环外,注意需求,否则可能导致值被覆盖,或者没有更新值
- 前端报错,记得在页面查看报错信息
- 写后台接口的时候注意前端传过来的参数格式和数据是否正确
- 可以根据返回值直接判断是否空,转换思维
- 发现报错到不了后台,一定要注意查看请求路径!!!是否跟后台一致
- 在后台添加完字段记得重启!!!
- 注意看请求的值
- 找位置先找到对应的页面
- 前端起不来,npm install
- 思路转变,找到PageAction页面不同的值,直接加上判断或即可,找问题首先定位到当前的页面找到再查看对应的值
- 注意保存的时候的值,还有关联的上下代码
- 注意case一定要有break
- 主要还是使用equals比==好
- (“深圳分部”).equals(departmentName) 位置调换,避免空指针
- foreach循环 return false只是终止当前循环
- for循环 return false 才是终止所有循环
- 注意事项:添加完枚举之后,先查看后台的值数据有无值,记得强刷页面获取值
- mybatis-plus:使用自带字段的时候发现没法查询数据,注意查看实体注解是否添加value可以对应查数据库的值
- bigint对应的是long类型
- 一般前端有值,各种显示不出来,应该都是因为类型不对问题(比如:int和string)
@TableField(fill = FieldFill.INSERT,value = "create_user_name")
private String createUserName;
第一周
2022.3.20
-
启动vue项目
-
下载对应的maven包
-
idea跳转到当前文件夹(到当前项目目录根路径)
-
dbeaver数据库连接工具
2022.3.21 -
查看关闭当前进程
netstat -ano:查询当前在运行的端口进程
taskkill /F /PID pid号:关闭进程
-
根据请求路径查找方法
-
Ctrl+shift+f9:外置Tomcat编译
2022.3.22
- 数据库连接:
- 在idea启动第一行有连接数据库的信息
url: jdbc:mysql://m.championsoft.net:27336/jczx_business?useSSL=false&useUnicode=true&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&characterEncoding=UTF-8
username: root
password: ****
域名:m.championsoft.net
数据库名:jczx_business
- Ctrl+h 全文搜索替换
- 工作流activitis
- processEngline:工作流核心引擎
- 主要类:workflowController
- 注意替换流程图尾缀要合法
- 代码生成器
2022.3.24 - 前端报500错误,后台报模板无法识别(加上@ResponseBody)
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [lab/staffSupervisionPlan/
- 注解 @ResponseBody,使用在控制层(controller)的方法上。
作用
作用:将方法的返回值,以特定的格式写入到response的body区域,进而将数据返回给客户端。
当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。
如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。
-
使用vue向后台传参数的时候,记得先在data(){里面定义}
-
可以在绑定事件里面添加函数方法
:on-success="uploadSuccess"--> uploadSuccess(resp) { this.attachmentId = resp.attachmentId; this.importData('importForm'); },
-
vue 根据判断状态,显示数据
<qm-table-column field="qualified" show-overflow min-width="160">是否合格
<template v-slot:content="{ row }">
<span v-if="row.qualified == 0">不合格</span>
<span v-else-if="row.qualified == 1">合格</span>
<span v-else>-</span>
</template>
</qm-table-column>
- exprot class如果继承了controller,就要写mixin
- 工作流这几个属性要传到后台
- 模板添加库:在这个表里添加一下模板数据,code_generator
- 返回提示信息给前台
resultHolder.get().setSuccess(true); resultHolder.get().setMessage("供应商名称重复!");
- 数据库工具类判空:
CollectionUtils
- vue引进函数:
"model.phone": pattern.telephone(),
-
注意事项:vue页面改了无刷新无反应,证明改的不是本页面
-
报500错误,模板错误,可能因为没有返回json给前端,加上@requescontroller全局或者@responsebody
-
注意空格 前端
-
返回提示信息给前台
resultHolder.get().setSuccess(true);
resultHolder.get().setMessage("供应商名称重复!");
- string数组转list
如果是String数组,可以使用Stream流这样转换:
String[] arrays = {"黄苑军", "黄苑军", "廖柳凤"};
List<String> stringList= Stream.of(arrays).collect(Collectors.toList());
- 下拉框多选加这三个属性
- multiple
filterable
clearable- - 在对应的controller重写这个方法便可以使用自定义的xml执行多表查询
@Override
protected boolean multiTable() {
return true;
}
- 数组工具类判空
CollectionUtils
- win11快速剪切:win+v
if判断: v-if="models.model.basis!=null && models.model.basis.indexOf(4)!=-1 "
:disabled="models.model.status != 3 || custPageAction == 'view'"
找到其父组件判断是否显示按钮: :show-edit="taskCode!='usertask5'"(思路:可以先塞值(true,false)判断是否生效,再真实传值)
-
注意写枚举类多个值前面都是英文,最后一个才是英文;不然会报错
-
这是后台buildViewModel返回的数据(在预览controllerdata里面)
-
附件上传(要同一页面保存不同的附件的话,就改变bizType)
<el-row>
<el-col :span="24">
<el-form-item label="附件上传:">
<qm-file-upload
:dataKey="models.model.id"
bizType="projectManagement"
:editable="pageAction != 'view'"
:fileList="fileList"
:uploadFiles="fileList"
title="附件上传"
fileSize="20"
fileType=".jpg,.png,.doc,.docx,.xls,.xlsx,.pdf,.txt,.zip,.rar"
@uploaded="uploadSuccess"
></qm-file-upload>
</el-form-item>
</el-col>
</el-row>
import QmFileUpload from "@/libs/components/qm-file-upload"
components: {
QmFileUpload,
},```
- 如果引入路径没有变色,就要components里面引入定义即可
```js
components: {
QmFileUpload,
},
- 根据对应的返回状态返回是否需要填写值(disabled)
- 转成list集合
转化成list集合
collect(Collectors.toList());
List<String> collect =departmentList.stream().map(TaskDepartment::getDepartmentId).collect(Collectors.toList());
- 在前端设置好默认的是否选择值,省事不用在后台再弄枚举
<el-row>
<el-col :span="12">
<el-form-item label="是否外聘:">
<el-radio-group v-model="models.model.external">
<el-radio :label="0">是</el-radio>
<el-radio :label="1">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="models.model.external == '0'">
<el-col :span="12">
<el-form-item label="姓名:" prop="model.name">
<el-input v-model="models.model.name" placeholder="请输入姓名" maxlength="25" show-word-limit></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="单位:" prop="model.unit">
<el-input v-model="models.model.unit" placeholder="请输入单位" maxlength="50" show-word-limit></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职称:" prop="model.jobTitle">
<el-input v-model="models.model.jobTitle" placeholder="请输入职称" maxlength="100" show-word-limit></el-input>
</el-form-item>
</el-col>
</el-row>
-
安装淘宝npm镜像:npm install -g cnpm --registry=https://registry.npm.taobao.org
-
在service写接口最主要是为了其他类直接引入service调用它(高可用)
-
测试终止流程空指针判断
Object o= null;
o.equals("");
- 代码传参复用
iStaffSupervisionPlanService.terminatePlan(formData.getPlanId(), "综合室主任已完成评价",SpotSupervisionProcessStatusEnum.CHECKED.getValue());
void terminatePlan(Long planId, String workflowComment,Integer status);
@Override
public void terminatePlan(Long planId, String workflowComment, Integer status) {
//获取工作流参数
Map<String, Object> content = workflowUtils.getWorkflowArgs(null, planId + "", null);
if (!content.isEmpty()) {
workflowUtils.processTerminate(MapUtils.getString(content, "instanceId"), workflowComment);
//更新人员监督计划状态
StaffSupervisionPlan supervisionPlan = this.getById(planId);
supervisionPlan.setPlanId(planId);
supervisionPlan.setStatus(status);
this.updateById(supervisionPlan);
}
}
Map<String, String> getNumberByPlanId(Long planId,Integer status);
@Override
public Map<String, String> getNumberByPlanId(Long planId,Integer status) {
return baseMapper.getNumberByPlanId(planId,status);
}
Map<String, String> getNumberByPlanId(@Param( "planId" )Long planId, @Param( "status" )Integer status);
<select id="getNumberByPlanId" resultType="java.util.Map">
select sum(if(sspd.status = #{status},1,0)) as completedNumber, count(*) as totalNumber
from staff_supervision_plan_detail sspd
left join staff_supervision_staff sss on sss.plan_detail_id = sspd.plan_detail_id
where 1=1
and sss.user_type = 1
and sspd.plan_id = #{planId}
</select>
- Select 选择器(注意前后端类型)
<el-col :span="12">
<el-form-item label="是否收费:" prop="model.isFee">
<el-select v-model="models.model.isFee" placeholder="请选择是否收费">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
options: [{
value: 0,
label: '不收费'
}, {
value: 1,
label: '收费'
}],
- stream流判断
String userIds = train.stream().filter(tran -> tran.getPrincipalUserId()!=null)
.map(TrainPlanDetail::getPrincipalUserId).collect(Collectors.joining(","));
- 前端传过来字符串转数组
获取前端传过来的数据
String listString = request.getParameter("domains");
Long recordId = Long.valueOf(request.getParameter("model[recordId]"));
List<TrainRecordDetailed> list = (List<TrainRecordDetailed>) objectMapper.readValue(listString,TrainRecordDetailed.class);//字符串转数组
List<TrainRecordDetailed> list = objectMapper.readValue(listString, new TypeReference<List<TrainRecordDetailed>>() {});//字符串转数组
- 迭代器Iterator
Iterator<TrainRecord> iterator = records.iterator();
while(iterator.hasNext()){
TrainRecord trainRecord = iterator.next();
List<TrainRecordDetailed> trainRecordDetailedList = trainRecordDetailedService.lambdaQuery().eq(TrainRecordDetailed::getRecordId,trainRecord.getRecordId()).list();
trainRecord.setDomains(trainRecordDetailedList);
}
-
页面里面的输入框判断填写才能提交
-
let qm = this.$refs.qmDetailList;这个是获取上面列表的数据
-
<qm-workflow
ref="qmWorkflow"
:rules="rules"
@done="qmWorkflowDone"
key-prop="planId"
:otherParams="otherParams"
:other-validate="otherValidate"
:jumpSelectUserAndComment="
models.model.status == 3 ? true : models.model.status == 5 ? true : false
"
:form-option="{ labelWidth: '180px' }"
:beforeSaveWorkflowFunc="beforeSaveWorkflowFunc"
>
<el-card class="box-card">
<div slot="header" class="clearfix"><span>监督计划</span></div>
<el-form>
<detailList
ref="qmDetailList"
:planId="
models.model.planId ? models.model.planId.toString() : ''
"
:planCode="models.model.planCode"
:planName="models.model.planName"
:year="models.model.year"
:cuPageAction="pageAction"
:status="models.model.status"
></detailList>
</el-form>
</el-card>
beforeSaveWorkflowFunc(callback, arg1, arg2) {
if (arg2) {
let qm = this.$refs.qmDetailList;
if (qm.query && qm.query.data && qm.query.data.length === 0) {
this.$message.error("监督计划不能为空,请添加监督计划!");
return false
}
}
this.$nextTick(() => {
callback.call(this, arg1, arg2);
});
}
- 通过路径跳转页面(人员监督)
- 查找当前所有部门
viewModel.getControlData().put("departments", iSysDepartmentService.getBaseMapper().selectList(null));
-
在mysql中mul是Key,而key是键的意思,key分为主键primary key,外键FOREIGN KEY以及一般键,当Key是MUL时,那么该列的值可以重复,并且该列是一个非唯一索引的前导列。
-
自定义上传附件按钮隐藏
:editable="models.model.status == 5"
- 获取当前参与当前培训所有人员
List<String> userLoginIdList = externalTrainUserService.list(new QueryWrapper<ExternalTrainUser>()
.eq("train_id", formData.getTrainId()))
.stream()
.map(ExternalTrainUser::getLoginId)
.collect(Collectors.toList());
- 遍历返回对应的枚举值
public static Integer getNameByValue(String name) {
for (ExternalTrainRoomTypeEnum typeEnum : values()) {
if (name.equals(typeEnum.getName())) {
return (typeEnum.getValue());
}
}
return null;
}
- 下拉框查询
<el-form-item label="状态:">
<el-select v-model="search.state" placeholder="请选择">
<el-option
v-for="item in controlData.equipmentVerificationCalibrationProcessStatusOptions"
:key="item.value"
:label="item.key"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
- 是否显示
computed:{
showReview(){
return this.models.model.status !== 0 && this.models.model.status !== 1;
},
showAllocateUser(){
return this.models.model.status !== 0 && this.models.model.status !== 1 && this.models.model.status !== 3 && this.models.model.status !== 4;
},
reviewEdit(){
return this.pageAction === 'edit' && (this.controlData.workflow.taskCode === 'usertask2' || this.controlData.workflow.taskCode === 'usertask6');
},
allocateUserEdit(){
return this.pageAction === 'edit' && this.controlData.workflow.taskCode === 'usertask3'|| this.controlData.workflow.taskCode === 'usertask7';
},
},
<el-row v-if="showAllocateUser">
- ArrayList判断里面数值字段是否相等并分类
public Map<String, List<ApplySampleAndTaskDetailVO>> getNationalControlPointTaskDetail(String taskId) {
Map<String,List<ApplySampleAndTaskDetailVO>> map = new HashMap<>();
List<ApplySampleAndTaskDetailVO> pointTaskDetails = baseMapper.getNationalControlPointTaskDetail(taskId);
for (ApplySampleAndTaskDetailVO applySampleAndTaskDetailVO : pointTaskDetails) {
//如果是国控点任务单的数据,就按样品分类好返给前端 task_type=3
Task task = iTaskService.lambdaQuery().eq(Task::getTaskId, applySampleAndTaskDetailVO.getTaskId()).one();
if (task.getTaskType().equals(3)) {
String keyVo = getApplySampleAndTaskDetailVOKey(applySampleAndTaskDetailVO);//获取需要判断是否相等的字段作为key
List<ApplySampleAndTaskDetailVO> voList = map.get(keyVo);
if (CollectionUtils.isNotEmpty(voList)) {
voList.add(applySampleAndTaskDetailVO);
map.put(keyVo, voList);
} else {
List<ApplySampleAndTaskDetailVO> newList = new ArrayList<>();
newList.add(applySampleAndTaskDetailVO);
map.put(keyVo,newList);
}
}
}
return map;
}
//根据遍历的vo获取对应需要判断的字段
String getApplySampleAndTaskDetailVOKey(ApplySampleAndTaskDetailVO applySampleAndTaskDetailVO){
return applySampleAndTaskDetailVO.getSampleDeadline()+applySampleAndTaskDetailVO.getSpotName()+applySampleAndTaskDetailVO.getObjectName()+applySampleAndTaskDetailVO.getSampleTypeName();
}
- 判断访问路径
:disabled="models.model.status != 3"
end
- 排序
Collections.sort(sites); // 字母排序
- 多个判断可以直接在同一行写(&&)
if(a.getSourceCodeId()!=null && a.getSourceCodeId().indexOf(item.getItemId()) > -1){
- 载荷
- post请求,表单形式,后台直接接收即可
.post("/lab/internalAuditPlan/removeSchedule", {scheduleId:domains.scheduleId})
public Result remove( String scheduleId){}
- 接收数据注解(转换思维),数据循环判断
- @RequestBody(绑定参数,接收json)
//查询计划明细数据
@RequestMapping("/selectDetail")
public boolean selectDetail(@RequestBody List<String> idList) {
for (String planDetailId : idList) {
TrainRecord record = trainRecordService.lambdaQuery().eq(TrainRecord::getPlanDetailId, planDetailId).one();
if (StringUtils.isEmpty(record)) {
return false;
}
}
return true;
}
- 接收前端传过来的参数
String listString = request.getParameter("domains");
- 遍历获取传入的id集合,得到其登录id
departmentIdsStr = request.getParameter("departmentIds");
if (!StringUtils.isEmpty(departmentIdsStr)) {
for (String deptId : departmentIdsStr.split(",")) {
users.addAll(sysUserService.getDepartmentManagerLoginIds(deptId));
}
}
- 时间输入框选择限制
:picker-options="{
disabledDate: (data) =>
models.model.planStartDate
? data < new Date(models.model.planStartDate)
: false,
}"
- 导入导出的注解的值要一一对应
@Excel(name = "负责科室",orderNum = "7",width = 24.82)
- 0为false,1为true
- return Boolean值
@Override
public boolean isFinished(String instanceId, String taskCode) {
//查找会签节点 流程状态为finished && 处理人不是当前人 的流程明细,如果找到则说明会签未完成
Long count = actExtWorkItemService.lambdaQuery()
.eq(ActExtWorkItem::getInstanceId, instanceId)
.eq(ActExtWorkItem::getTaskCode, taskCode)
.ne(ActExtWorkItem::getAssigneeId, Framework.getCurrentUser().getUserId())
.ne(ActExtWorkItem::getTaskStatus, ActExtWorkItem.WfTaskStatus.finished)
.ne(ActExtWorkItem::getTaskType, ActExtWorkItem.WfTaskType.noticeTask)
.count();
return count == 0;
}
- split分割数据字符单个查找
String[] projectNames = anImport.getProjects().split(",");
List<String> projectNameList = Arrays.asList(projectNames.clone());
if (CollectionUtils.isNotEmpty(projectNameList)) {
for (String project : projectNameList) {
StaffSupervisionMonitoringProject s3 = new StaffSupervisionMonitoringProject();
DetectProject detectProject = iDetectProjectService.getEntityByName(project);
if (detectProject == null) {
result.setSuccess(false);
result.setMessage("你在第" + num + "行,第四列导入的监督项目在系统中不存在!");
continue;
}
- BigDecimal数值比较
BigDecimal referencePrice=entity.getReferencePrice();
referencePrice.compareTo(new BigDecimal(50000))==0 等于50000
referencePrice.compareTo(new BigDecimal(1000))==-1 小于1000
referencePrice.compareTo(new BigDecimal(10000))>-1 大于10000
- 前端加await同步,需要接受數據
const res = await this.getDetailList(dettailList[i].planDetailId)
- 给一个list<实体>数组塞一个空的对象
List<InternalAuditPlanSchedule> domains = new ArrayList<>();//先new一个list数组
domains.add(new InternalAuditPlanSchedule());//给他塞一个空的对象,不需要返回值直接塞就行
entity.setDomains(domains);
- 导入导出官网:http://doc.wupaas.com/docs/easypoi/easypoi-1c2cp5rf3hnqv
- modelData从list页面传值到create页面
:modelData="{ workflowTaskCode: workflowArgs.taskCode, status: status }"
- 配置文件地址
get和post请求
- 最大的区别:最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数
- 传送方式:get通过地址栏传输(安全性较差),post通过报文传输。
- GET参数通过URL传递,POST放在Request body中。
- 加了requestbody注解,要使用post请求接收参数
- api接口调试访问不到后台,可能是因为没有开权限
IO流
for循环
- map 遍历,if反向判断 continue和 break
List<ApplySampleAndTaskDetailVO> pointTaskDetails = baseMapper.getNationalControlPointTaskDetail(taskId, task, isAudit);
//根据ApplySampleAndTaskDetailVO属性字段分组,分样品
Map<String, List<ApplySampleAndTaskDetailVO>> collect = pointTaskDetails.stream()
.collect(Collectors.groupingBy(a -> a.getSpotName() + "=" + a.getObjectName() + "=" + a.getSampleDeadline() + "=" + a.getSampleTypeName() + "=" + a.getSampleCode()));
int sampleNums = 0;//根据样品分类,查出sampleProcessStatus=5,则证明采样完成,否未采样样品未完成+1
for (String s : collect.keySet()) {
for (ApplySampleAndTaskDetailVO applySampleAndTaskDetailVO : collect.get(s)) {
if (applySampleAndTaskDetailVO.getSampleProcessStatus() != null && applySampleAndTaskDetailVO.getSampleProcessStatus() == 5){
continue;
}
sampleNums++;
break;
}
}
System.out.println("+++++++++++采样"+sampleNums);
for循环和foreach循环(效率高)
- 定义:foreach又叫做增强for循环,相当于for循环的简化版,因此在一些较复杂的循环中不适用。
- 特点:foreach在循环次数未知或者计算起来较复杂的情况下效率比for循环高。
String[] str={"a","b","c","d"};
for循环:
for (int i=0;i<str.length;i++) {
if("c".equals(str[i])){
str[i]="a";
}
}
for (String s : str) {
System.out.print(s);
}
结果:abad
foreach循环:
for (String ss : str) {
if("c".equals(ss)){
ss="a";
}
}
for (String s : str) {
System.out.print(s);
}
结果:abcd
枚举
-
枚举类名建议带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开.枚举其实是特殊的常量类,且构造方法被默认强制私有.
-
枚举类不需要set方法所以不用加@data注解,加上
-
@Getter @AllArgsConstructor
接收参数
- request注入
@Autowired
protected HttpServletRequest request; // 自动注入request ,线程安全的
-
from就是对应每一个参数,json对应就是后台一个实体接收
-
后端接口API需要的参数格式为json,但我们前端提交的数据格式为form表单
-
加了@RequestBody就代表json接收
@RequestBody SiteScheduling siteScheduling
- 实体接收参数
public Result forwardBatch(@RequestBody ForwardDTO forwardDTO) {
return baseService.forwardBatch(forwardDTO);
}
- 需要通过
HttpServletRequest request
请求获取数据,可以在controller获取到再传参
public IPage<TaskDTO> findAppNationalControlPointToDoList(HttpServletRequest request) {
//国控点更多模糊查询
String taskInfo = request.getParameter("model[task]");
PagerInfo<TaskDTO> pagerInfo = null;
try {
pagerInfo = QueryHelper.query(this.request, TaskDTO.class, new QueryHelper.QueryCallback<TaskDTO>() {
@Override
public void query(PagerInfo<TaskDTO> pagerInfo, QueryWrapper<TaskDTO> qw) throws Exception {
baseService.findAppNationalControlPointToDoList(pagerInfo, qw, taskInfo);
}
});
} catch (Exception e) {
logger.error("获取代办数据异常:{}", e.getMessage(), e);
}
List<TaskDTO> taskDTOS = pagerInfo.getRecords();
for (TaskDTO taskDTO : taskDTOS) {
Long taskDTOTaskId = taskDTO.getTaskId();
//根据不同的工作流fromId返回对应得taskId和对应工作流流程的主键id
if ("Sample".equals(taskDTO.getAppCode())){
Sample sample = iSampleService.getById(taskDTOTaskId);
if (sample.getTaskId()!=null) {
taskDTO.setSampleId(sample.getSampleId());
taskDTO.setSample("true");
taskDTO.setTaskId(sample.getTaskId());
//根据taskId返回项目名称和任务编号
Task task = baseService.getById(sample.getTaskId());
if (task != null){
taskDTO.setProjectName(task.getProjectName());
taskDTO.setTaskCode(task.getTaskCode());
taskDTO.setTaskType(task.getTaskType());
}
}
}else if ("SamplingRecord".equals(taskDTO.getAppCode())){
SamplingRecord samplingRecord = iSamplingRecordServicel.getById(taskDTOTaskId);
if (samplingRecord != null){
Sample sample = iSampleService.getById(samplingRecord.getSampleId());
if (sample!=null && samplingRecord != null && sample.getTaskId() != null){
// taskDTO.setSampleRecord("true");
taskDTO.setSamplingRecordId(samplingRecord.getSamplingRecordId());
taskDTO.setTaskId(sample.getTaskId());
//根据taskId返回项目名称和任务编号
Task task = baseService.getById(sample.getTaskId());
taskDTO.setProjectName(task.getProjectName());
taskDTO.setTaskCode(task.getTaskCode());
taskDTO.setTaskType(task.getTaskType());
}
}
}else if ("labMeasure".equals(taskDTO.getAppCode())){
DetectRecord detectRecord = detectRecordService.getById(taskDTOTaskId);
if (detectRecord!=null){
TaskDetail taskDetail = taskDetailService.getById(detectRecord.getTaskDetailId());
if (taskDetail!=null){
taskDTO.setTaskId(taskDetail.getTaskId());
//根据taskId返回项目名称和任务编号
Task task = baseService.getById(taskDetail.getTaskId());
taskDTO.setProjectName(task.getProjectName());
taskDTO.setTaskCode(task.getTaskCode());
taskDTO.setTaskType(task.getTaskType());
}
}
}
}
return pagerInfo;
}
- 后台result
String msg = "无法进行提交操作,当前未完成的有:【" + sampleNums + "】个采样任务、"
+ "【" + labPretreatmentNum + "】个前处理任务、"
+ "【" + beneficiationSeparationNum + "】个富集分离任务、"
+ "【" + detectRecordNum + "】个测量任务";
result.setSuccess(false);
result.setMessage(msg);
-
- 后台获取前端参数数据:
String documentId = request.getParameter("query[documentId]");
- 后台获取前端参数数据:
-
注意实体类中的属性名称必须与JOSN串中的参数key名称完全一致,不同命参数无法正确接收;
-
HttpServletRequest request接收参数 (request.getParameter(“name”))
判断
- int 数值类型用 == 判断
- 基本数据类型用equals判断
- if()判断多条件,前面条件false后面的条件就不会再走
- StringUtils.hasText():如果字符序列不为 null 值,并且字符序列的长度大于 0 ,并且不含有空白字符序列,则返回 true
- 字符串类型一般都用equals判断,数值基本类型一般用 == 判断
- while(rs.next()) //就是 将rs全部进行读取
- if(rs.next()) //rs进行读取一次 判断是否有数据
数据库
-
实体类PO:对应数据库字段(实体类对象)
-
实体类VO:主要对应展示页面显示的数据对象,用一个VO对象来封装展示所需要的对象数据,主要用于PO到DTO,或者DTO到PO的转换(数据传输对象,页面所需要的封装数据)
-
实体类DTO:对应页面显示字段
-
DBCP:是一个依赖Jakarta commons-pool对象池机制的数据库连接池。
-
C3P0:是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
-
Druid:阿里的Druid,不仅是一个数据库连接池,还包含一个ProxyDriver、一系列内置的JDBC组件库、一个SQL Parser。
-
Proxool:是一个Java SQL Driver驱动程序,它提供了对选择的其它类型的驱动程序的连接池封装,可以非常简单的移植到已有代码中。
-
sql条件查询,输入框所有条件
<if test="task != null">
AND (inst.instance_title LIKE concat('%',#{task},'%')
OR t.project_name LIKE concat('%',#{task},'%')
OR t.task_code LIKE concat('%',#{task},'%'))
</if>
- resultType:数据库返回的数据
resultType="com.qm.boot.web.business.lab.entity.Task"
- parameterType:为输入参数
- @Param和parameterType 二者存其一即可。看名字就能知道ParameterType是按照类型进行匹配,而@Param是按照名字进行匹配。
进程线程
进程与线程*
-
进程是操作系统资源分配的最小单位,线程是CPU调动的最小单位
-
一个进程可以包括多个线程
注解
-
- 日志打印注解@Slf4j
log.error(e.getMessage());
- 日志打印注解@Slf4j
-
时区问题注解:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
-
mysql模糊查询注解
@TableField(value = "task_name")
-
接收对象参数使用@RequestBody
-
接收单个参数使用@PathVariable
-
注解:谨记在后台加上时间字段的时候记得加上注解
@JsonFormat(pattern = "yyyy-MM-dd")
格式化时间,否则前端无法显示(ps:改完项目需要重启) -
@RequestParam 接收url地址中的参数
-
@RequestBody 接收body中JSON字符串参数(推荐使用Post请求携带body参数)
- @RequestBody User user
-
注解id防止精度丢失注解: @JsonFormat( shape = JsonFormat.Shape.STRING )
-
@RequestBody (JiudiancanyinEntity jiudiancanyin)
-
@requestparam(),接收参数直接
- 默认值defaultValue
- required = false::不传值后台也不会报错,但是如果@requestparam( required = false)的括号中指定了基本数据类型
集合
- list根据时间排序
Collections.sort(pointTaskDetailsList, (o1, o2) -> o1.getSampleDeadline().compareTo(o2.getSampleDeadline()));
Map
- 遍历map
List<SampleInfoDTO> pointTaskDetailsList = new ArrayList<>();
for(String key: pointTaskDetailsMap.keySet()){
SampleInfoDTO infoDTO = new SampleInfoDTO();
String[] s = key.split("=");
infoDTO.setSpotName(s[0]);
infoDTO.setObjectName(s[1]);
infoDTO.setSampleDeadline(s[2]);
infoDTO.setSampleTypeName(s[3]);
infoDTO.setSampleCode(s[4]);
infoDTO.setList(pointTaskDetailsMap.get(key));
pointTaskDetailsList.add(infoDTO);
SampleInfoDTO
@Data
public class SampleInfoDTO {
private String spotName;
private String objectName;
private String sampleDeadline;
private String SampleTypeName;
private String sampleCode;
private List<ApplySampleAndTaskDetailVO> list;
}
Java时间类时间
- 时间类型
jdk1.7:date类型
jdk1.8:LocalDate 只保存年月日pattern="yyyy-MM-dd"
jdk1.8:LocalDateTime 保存年月日时分秒pattern = "yyyy-MM-dd HH:mm:ss"
- Calendar类,时间比较大小
public Result saveSiteSchedulingInFo(@RequestBody SiteScheduling siteScheduling) {
Result result = Result.ok();
try {
Calendar beginOnDuty = Calendar.getInstance();
SiteScheduling scheduling = new SiteScheduling();//数据库中没有数据的,直接赋值保存
//如果批量排班开始日期和批量排班结束日期不为空,就为批量设置,为空 就是单个设置保存或者新增
if (siteScheduling.getBeginOnDutyDate()!=null && siteScheduling.getEndOnDutyDate()!=null){
Date beginOnDutyDate = new SimpleDateFormat("yyyy-MM-dd").parse(siteScheduling.getBeginOnDutyDate());
Date endOnDutyDate = new SimpleDateFormat("yyyy-MM-dd").parse(siteScheduling.getEndOnDutyDate());
beginOnDuty.setTime(beginOnDutyDate);
while (beginOnDutyDate.before(endOnDutyDate)){
SiteScheduling scheduling1 = baseService.lambdaQuery().eq(SiteScheduling::getOnDutyDate,beginOnDutyDate).eq(SiteScheduling::getDepartmentType, siteScheduling.getDepartmentType()).one();
if (scheduling1!=null && scheduling1.getDepartmentType().equals(siteScheduling.getDepartmentType())){
scheduling1.setDepartmentType(siteScheduling.getDepartmentType());
scheduling1.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling1.setOnDutyDate(beginOnDutyDate);
baseService.saveOrUpdate(scheduling1);
}else {
scheduling.setSiteSchedulingId(IdUtil.getId());
scheduling.setDepartmentType(siteScheduling.getDepartmentType());
scheduling.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling.setOnDutyDate(beginOnDutyDate);
baseService.saveOrUpdate(scheduling);
}
beginOnDuty.add(Calendar.DAY_OF_MONTH, 1);//日期递增一天
beginOnDutyDate= beginOnDuty.getTime();
if (beginOnDutyDate.equals(endOnDutyDate)){//日期等于批量设置的最后一天,刷新或插入当天排班
SiteScheduling scheduling3 = baseService.lambdaQuery().eq(SiteScheduling::getOnDutyDate,beginOnDutyDate).eq(SiteScheduling::getDepartmentType, siteScheduling.getDepartmentType()).one();
if (scheduling3!=null && scheduling3.getDepartmentType().equals(siteScheduling.getDepartmentType())){
scheduling3.setDepartmentType(siteScheduling.getDepartmentType());
scheduling3.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling3.setOnDutyDate(beginOnDutyDate);
baseService.saveOrUpdate(scheduling3);
}else {
scheduling.setSiteSchedulingId(IdUtil.getId());
scheduling.setDepartmentType(siteScheduling.getDepartmentType());
scheduling.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling.setOnDutyDate(beginOnDutyDate);
baseService.saveOrUpdate(scheduling);
}
}
}
}else {
SiteScheduling scheduling2 = baseService.lambdaQuery().eq(SiteScheduling::getOnDutyDate, siteScheduling.getOnDutyDate()).eq(SiteScheduling::getDepartmentType,siteScheduling.getDepartmentType()).one();
if (scheduling2!=null && scheduling2.getDepartmentType().equals(siteScheduling.getDepartmentType())){
scheduling2.setDepartmentType(siteScheduling.getDepartmentType());
scheduling2.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling2.setOnDutyDate(siteScheduling.getOnDutyDate());
baseService.saveOrUpdate(scheduling);
}else {
scheduling.setSiteSchedulingId(IdUtil.getId());
scheduling.setDepartmentType(siteScheduling.getDepartmentType());
scheduling.setPersonnelOnDutyId(siteScheduling.getPersonnelOnDutyId());
scheduling.setOnDutyDate(siteScheduling.getOnDutyDate());
baseService.saveOrUpdate(scheduling);
}
}
} catch (Exception e) {
result.setSuccess(false);
result.setMessage(e.getMessage());
log.error(e.getMessage());
}
return result;
}
后端代码
- 返回数据给前端提示
resultHolder.get().setSuccess(true);
resultHolder.get().setMessage("供应商名称重复!");
return false;
resultHolder.get().setSuccess(true);
resultHolder.get().setMessage("供应商名称重复!");
return false;
StringBuffer 、StringBuilder、string 区别
- string每次修改会创建新的对象
- StringBuffer 和 StringBuilder每次修改对象本身操作,不会生成新的对象
- StringBuffer 和 StringBuilder最大的区别 StringBuffer 是线程安全
- StringBuilder有速度优势,所以多数情况下建议使用
- test
public class RunoobTest{
public static void main(String args[]){
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(8, "Java");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
}
}
hashcode和equals的区别
- hashcode:hashcode就是一个签名。当两个对象的hashcode一样时,两个对象就有可能一样。如果不一样的话两个对象就肯定不一样
- equals:优先级比hashcode高,若两个对象equals相等,则hashCode也相同,我们需要确保当两个对象equals相等时,那么他们的hashcode一定相等。如果两个对象equals不相等,那么两个对象的 hashCode 方法不一定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能,若equals不相同,则hashCode不需要确保一定不相同。
HashMap和HashTable有何区别?
- hashmap:数组+链表,键值对可以为null,线程不安全
- hashtable:数据+链表,键值对都不能为null,线程安全
study
-
static静态方法可以直接调用
-
public方法需要new 调用
-
if(false) = false
-
逻辑删除与物理删除可以同时存在
-
迭代器可以修改数据,for循环修改不了
-
iterator
-
数据库为 BigDecimal类型,实体类中也是BigDecimal,如果为string的话会默认加上四位小数点(数据库数值几位,就回显几位小数)
-
“父类的方法不执行了,因为子类的方法已经覆盖了父类的方法
-
回调,看父类有调用哪些方法
@PostMapping("/processTerminate")
@ResponseBody
public Object processTerminate(String instanceId) {
Result result = resultHolder.get();
try {
transactionService.doWork(new TransactionWork() {
@Override
public boolean work() throws Exception {
if (!beforeWorkflowTerminate(instanceId)) {
return false;
}
// 修改任务状态为完成
String comment =
"流程已被 " + Framework.getCurrentUser().getDisplayName() + " 终止,原因:" + getWorkflowComment();
List<ActExtWorkItem> actTasks = actExtWorkItemService.list(new QueryWrapper<ActExtWorkItem>()
.eq("INSTANCE_ID", instanceId).eq("TASK_STATUS", WfTaskStatus.processing.name()).or().eq("TASK_STATUS", WfTaskStatus.pausing.name()));
actTasks.forEach(a -> {
a.setFinishTime(LocalDateTime.now());
a.setTaskStatus(WfTaskStatus.finished);
a.setOpinionText(comment);
a.setHandlerId(a.getAssigneeId());
a.setHandlerName(a.getAssigneeName());
actExtWorkItemService.update(a, new QueryWrapper<ActExtWorkItem>().eq("TASK_ID", a.getTaskId())
.eq("ASSIGNEE_ID", a.getAssigneeId()));
});
// 修改实例 状态为终止
ActExtWorkInst instance = actExtWorkInstService.getById(instanceId);
instance.setStatus(WfInstanceStatus.terminated);
instance.setFinishTime(LocalDateTime.now());
actExtWorkInstService.updateById(instance);
// 删除 activiti 的任务
workflowService.processEngine.getRuntimeService().deleteProcessInstance(instanceId, null);
if (!afterWorkflowTerminate(instanceId)) {
return false;
}
return true;
}
});
result.setSuccess(true);
} catch (Exception e) {
dbLogger.error(LogUtil.formatMessage("终止失败。", e), LogUtil.buildDefaultLogArgs());
e.printStackTrace();
result.setSuccess(false);
if (StringUtils.isEmpty(result.getMessage())) {
result.setMessage("服务器异常,请联系管理员!");
}
}
return result;
}
- try-catch
Result result = Result.ok();
try {
for (SiteScheduling siteScheduling : schedulingList) {
baseService.saveOrUpdate(siteScheduling);
}
} catch (Exception e) {
result.setSuccess(false);
result.setMessage(e.getMessage());
}
return result;
- return返回值,一个方法只会返回一次返回值,假如你写了多个return,他返回一个后,其他就不会返回了
public List<TaskDetail> getSampleAppDetail(String taskId, String taskDetailId) {
List<TaskDetail> detailList = lambdaQuery().eq(TaskDetail::getTaskId, taskId).list();
//根据ApplySampleAndTaskDetailVO属性字段,分组
Map<String, List<TaskDetail>> pointTaskDetailsMap = detailList.stream()
.collect(Collectors.groupingBy(a -> a.getSpotName() + "=" + a.getObjectName() + "=" + a.getSampleDeadline() + "=" + a.getSampleTypeName() + "=" + a.getSampleCode()));
for (String s : pointTaskDetailsMap.keySet()) {
for (TaskDetail taskDetail : pointTaskDetailsMap.get(s)) {
if (taskDetailId.equals(String.valueOf(taskDetail.getTaskDetailId()))) {
return pointTaskDetailsMap.get(s);
}
}
}
return detailList;
}
- 定时器,时间比较先后
/**
* 定时器每天早上七点三十分执行一次
* 判断标准管理到生效时间就生效
*/
// @Scheduled(cron = "*/60 * * * * ?") 60秒执行一次
@Scheduled(cron = "0 0,30 0,7 ? * ? ")
public void refresh() {
List<NormativeDocument> normativeDocumentList = baseService.lambdaQuery().select().list();
//当前时间
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd");
Date nowDate = new Date();
String format = ft.format(nowDate);
LocalDate nowdate = LocalDate.parse(format, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Date nowdate1 = Date.from(nowdate.atStartOfDay(ZoneId.systemDefault()).toInstant());
for (NormativeDocument normativeDocument : normativeDocumentList) {
LocalDate effectiveDate = normativeDocument.getEffectiveDate();//生效时间
if (effectiveDate != null){
//用date类型来比对是否生效,LocalDate转date
Date date1 = Date.from(effectiveDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
//时间比对,时间相等=0,在时间在后=1
int i = date1.compareTo(nowdate1);
if (i == 0 || i== 1) {
//到生效日期,刷新生效状态,保存到标准表和验证表
normativeDocument.setTakeEffectStatus(NormativeTakeEffectStatusEnum.EFFECTIVE.getValue());
baseService.saveOrUpdate(normativeDocument);
}
}
}
}
- 截串(取值)
String[] s = key.split("="); s[0]
-
\n:换行
-
命令下载依赖
-
给a实体赋值给b实体2BeanUtils.copyProperties(byId, normativeDocumentVerification);
-
属性用包装类尽量少用基本类型,基本类型值为0包装类为null
-
swith判断
switch (documnetType) {
case 0:
entity.setDocumnetCode("GERC-ZS-"+entity.getVersion()+"-"+year);
break;
case 1:
entity.setDocumnetCode("GERC-CX-"+entity.getVersion()+"-"+entity.getFileNumber()+"-"+year);
break;
case 2:
entity.setDocumnetCode("GERC-ZY-CG-"+entity.getVersion()+"-"+entity.getFileNumber());
break;
case 3:
entity.setDocumnetCode("GERC-YS-SS-CG-"+entity.getFileNumber());
break;
default:
break;
}
-
接收参数过多的话可以使用个DTO对象包装一下接受这些参数
-
返回数据不多的时候没必要返回整个实体,可以自定义dto实体封装数据,减少不必要消耗
-
实体类VO就是返回给前端视图的数据不用对应数据库,可以自定义各种类型,满足前端页面展示的需求,数据库一张表满足不了多需求
-
泛型T,什么类型用到它就是什么类型
-
HttpServletRequest对象request代表浏览器请求对象,HttpServletResponse对象代表服务器响应对象
-
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
-
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
-
Main 类中 main() 是一个静态函数, fun() 是一个非静态函数, Java 静态函数中不能调用非静态函数的方法。
class Main {
public static void main(String args[]) {
System.out.println(fun());
}
int fun()
{
return 20;
}
}
- Java 函数不允许参数设置默认值。
static int fun(int x = 0)
{
return x;
}