要实现的功能:新增之后根据查重结果前端会弹窗提示‘新增成功’或‘该条数据已存在,无需新增’,当有重复数据时在报错之前需要将两个项目名合并,原来是在后端写的通过throw new 抛出异常,但这种方式会回滚,因为有@Transactional(rollbackFor = Exception.class)注解在,这导致了抛异常后之前合并项目名总是回滚,并没有合并成功,然后组长说尽量在前端抛异常,但前端的新增的调用都封装在crud.js里,所以第一次尝试使用crud.js里的 CRUD.HOOK.beforeSubmit钩子在新增之前加个判断的方法:
@ApiOperation("新增需求之前")
@AnonymousPostMapping("/beforeCreate")
@AnonymousAccess
public ResponseEntity<Object> beforeCreate(String name,String version, Long osId, Long swId, Long projectId){
return new ResponseEntity<>(requirementService.beforeCreate(name,version,osId,swId,projectId), HttpStatus.OK);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> beforeCreate(String name,String version, Long osId, Long swId, Long projectId) {
Map<String,Object> map = new HashMap<String,Object>();
StringBuilder message = new StringBuilder();
//相同数据但项目名不同时将数据合并,项目名显示多个项目
String details = "";
Requirement requirements = requirementRepository.findByNameVersion(name,version);
if( requirements != null) {
if (requirements.getOs().getId() != osId){
Os os = osRepository.findByName("不限操作系统");
requirements.setOs(os);
}
if (requirements.getSw().getId() != swId){
Sw sw = swRepository.findByName("不限芯片版本");
requirements.setSw(sw);
}
//出现同名需求一次 则增加10优先级
int pri = requirements.getPriority()+10;
if (pri>100){
pri = 100;
}
requirements.setPriority(pri);
//新增时多选的项目
Set<Project> projects1 = requirements.getProjects();
List<Long> projectIds = new ArrayList<>();
Iterator<Project> it2 = projects1.iterator();
projectIds.add(projectId);
while (it2.hasNext()) {
if (projectIds.get(0) == it2.next().getId()) {
projectIds.remove(0);
break;
}
}
if (projectIds.size() != 0) {
for (int m = 0; m < projectIds.size(); m++) {
int len = requirementRepository.addRequirementProject(requirements.getId(), projectIds.get(m));
System.out.println(len);
}
}
if (requirements.getExamine().equals("已拒绝")){
requirements.setExamine("未审核");
requirements.setModular("审核");
String create_by = SecurityUtils.getCurrentUsername();
requirements.setCreateBy(create_by);
requirementRepository.save(requirements);
details = "新增成功!";
map.put("ret",1);
message.append(details);
map.put("msg",message.toString());
return map;
}else {
details = "您录入的"+requirements.getName()+"需求已存在,并在"+requirements.getModular()+"模块中合并,无需重复录入!";
map.put("ret",1);
message.append(details);
map.put("msg",message.toString());
return map;
}
}
map.put("ret",0);
message.append("无相同需求");
map.put("msg",message.toString());
return map;
}
async beforeCreated(name, version, osId, swId, projectId) {
let formData = new FormData();
let mon
formData.append("name", name)
formData.append("version", version)
formData.append("osId", osId)
formData.append("swId", swId)
formData.append("projectId", projectId)
await axios({
method: "post",
url: "/api/requirements/beforeCreate",
headers: {
"Content-type": "multipart/form-data",
Authorization: getToken(),
},
data: formData,
}).then(
(res) => {
mon = res.data.ret
this.retu = res.data.ret
if (res.data.ret === 1) {
this.$message.warning(res.data.msg)
}
},
(err) => {
}
);
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(mon)
},3)
})
},
[CRUD.HOOK.beforeSubmit](crud, form) {
let name = this.form.demands[0].name
let version = this.form.demands[0].version
let osId = this.form.os.id
let swId = this.form.sw.id
let projectId = this.form.projects[0].id
let mon = this.beforeCreated(name,version,osId,swId,projectId)
// .then(res => {
// this.retu = res
// console.log('11111111111',this.retu)
// });
console.log('mon',mon.then())
console.log('这里没执行吗')
console.log('222222',this.retu)
// if (this.retu === 1){
return false
// }
},
但,用这个方法研究了整整一天的我,最终还是放弃了,因为在CRUD.HOOK.beforeSubmit方法中代码段的运行是异步的,按理说JavaScript中的方法都是异步执行的,这导致了每次我想取的mon值每次都取不到,取之后才进行赋值操作,非常头疼,然后用async await实现代码按顺序执行,能取到值了,但对于CRUD.HOOK.beforeSubmit的return false又失效了,CRUD.HOOK.beforeSubmit需要通过return false去不执行接下来的新增操作,
/**
* 执行添加
*/
doAdd() {
if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) {
return
}
crud.status.add = CRUD.STATUS.PROCESSING
crud.crudMethod.add(crud.form).then(() => {
crud.status.add = CRUD.STATUS.NORMAL
crud.resetForm()
crud.addSuccessNotify()
callVmHook(crud, CRUD.HOOK.afterSubmit)
crud.toQuery()
}).catch(() => {
crud.status.add = CRUD.STATUS.PREPARED
callVmHook(crud, CRUD.HOOK.afterAddError)
})
},
感觉走了一条死路,最后为了实现这个功能,我还是在后端抛出了异常返回给前端,不过这次我没有在service里抛异常,因为service有回滚的注解,而是在Controller层直接判断+抛异常,
@Log("新增需求")
@ApiOperation("新增需求")
@PostMapping
@PreAuthorize("@el.check('requirement:add')")
public ResponseEntity<Object> create(@Validated @RequestBody RequirementDto resources) throws Exception {
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
String details = requirementService.beforeCreate(resources);
if (!details.equals("")){
throw new BadRequestException(details);
}
requirementService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
走完这一遭感觉真心累,异步方法里还有异步,使用async又不能return false,CRUD钩子函数定义成同步,return会失效。
分割线————————————————————————————————————————
刚刚把这个问题解决了,还是在前端抛的异常,经群里大佬提示,加了个自定义验证方法,在rules里通过validator去实现自定义验证,然后就没有异步这些问题了。
rules: {
projects: [
{ required: true, trigger: 'blur', validator: validRequirement }
]
}
// 自定义验证
const validRequirement = (rule, value, callback) => {
if (this.crud.status.edit === CRUD.STATUS.PREPARED){
callback()
}
let name = this.form.demands[0].name
let version = this.form.demands[0].version
let osId = this.form.os.id
let swId = this.form.sw.id
let projectId = this.projectDatas[0]
this.beforeCreated(name,version,osId,swId,projectId).then(res => {
if(res === 0){
callback()
}
});
}