公司study two

工作流

方法

  • 重写了这个方法就默认是用自己的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前端不同页面传值
    1. 在对应的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";
  1. 在data里面定义要传的值
      data() {
        return {
          util: Util,
          recordListModalVisiable: false,
          planDetailId: "",
          name: "",
          unit: "",
          trainAddress: "",
          planStartDate: "",
          planEndDate: "",
        };
      },
  1. 写对应的行方法获取到他们的值
     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;
        },
  1. 在接收数据页面,接收值
//给页面初始化的时候赋值  
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'"(思路:可以先塞值(truefalse)判断是否生效,再真实传值)
  • 引入函数正则表达式
"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>
  • 导出数据库CSV格式
    在这里插入图片描述
    在这里插入图片描述

  • MySQL Key值(PRI, UNI, MUL)的含义

  • PRI主键约束

    UNI唯一约束

    MUL可以重复

  • mysql直接把数据a盖到数据b

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>();
  • 数据结构:
    1. 数组结构(大小固定不易动态扩展,查读容易,增删难)
    2. 链表结构(插入删除速度快,内存利用率高,没有固定大小,扩展灵活,查找慢)
    3. 哈希表结构(结合数组结构和链表结构的优点,从而实现了查询和修改效率高,插入和删除效率也高的一种数据结构
      常见的HashMap就是这样的一种数据结构)
  • hashcode:hashcode就是一个签名。当两个对象的hashcode一样时,两个对象就有可能一样。如果不一样的话两个对象就肯定不一样

类型转换

  1. string转list
List<String> loginId = Arrays.asList(context.getCurrentWorkflowUser().getLoginId());
  1. 数据转换类型(转成实体)
EquipmentPurchase formData = (EquipmentPurchase) context.getFormData();
  1. 数组转list
String[] strArray = { "a", "b" };
List<String> strList = Arrays.asList(strArray);
  1. 把对象转成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串,然后写到客户端。

在这里插入图片描述

  1. 使用vue向后台传参数的时候,记得先在data(){里面定义}

  2. 可以在绑定事件里面添加函数方法

    :on-success="uploadSuccess"-->    uploadSuccess(resp) {
            	 				 this.attachmentId = resp.attachmentId;
           						 this.importData('importForm');
            					},
    
    
  3. 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>
  1. exprot class如果继承了controller,就要写mixin
  2. 工作流这几个属性要传到后台在这里插入图片描述
  3. 模板添加库:在这个表里添加一下模板数据,code_generator
  4. 返回提示信息给前台
    resultHolder.get().setSuccess(true); resultHolder.get().setMessage("供应商名称重复!");
  5. 数据库工具类判空:CollectionUtils
  6. 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'"(思路:可以先塞值(truefalse)判断是否生效,再真实传值)
  • 注意写枚举类多个值前面都是英文,最后一个才是英文;不然会报错

  • 这是后台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)
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCzlSdxm-1650678134505)(C:\Users\86151\AppData\Roaming\Typora\typora-user-images\image-20220422102021580.png)]
  • 转成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调动的最小单位

  • 一个进程可以包括多个线程

注解

    • 日志打印注解@Slf4jlog.error(e.getMessage());
  • 时区问题注解:@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.8LocalDate 只保存年月日pattern="yyyy-MM-dd"
jdk1.8LocalDateTime 保存年月日时分秒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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java中的战斗机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值