修复Spring注解冲突和参数绑定问题

解决问题:
- 修复"No primary or single unique constructor found for interface java.util.Map"运行时错误
- 消除8个控制器的通配符导入引起的注解冲突
- 提升代码类型安全性和标准合规性

主要修改:
1. 控制器注解修复 (8个文件):
   - 将通配符导入(import org.springframework.web.bind.annotation.*)改为显式导入
   - 消除Spring @RequestBody与Swagger @RequestBody的注解歧义
   - 涉及: RepairController, AssignController, EngineerController, RepairTodoController等

2. 类型安全改进:
   - AssignController: 创建TaskListQuery DTO替换不安全的Map参数
   - 更新相关服务层、Mapper接口和XML查询以支持新DTO
   - 移除Map<String,Object>反模式,提升安全性

3. 配置修复:
   - application-prod.yml: 添加allow-circular-references=true解决循环依赖
   - 确保dev和prod环境配置一致性

4. 代码清理:
   - TaskHandleController: 清理未使用的导入
   - UserController: 移除冲突的Swagger RequestBody导入

技术收益:
- 消除了影响50%控制器类的系统性注解冲突问题
- 提升API参数类型安全性和验证能力
- 符合Java开发标准的显式导入最佳实践
- 解决了dev/prod环境切换时的运行时错误
This commit is contained in:
75681 2025-08-13 11:56:51 +08:00
parent ad9efdbdd8
commit 1a971abbb1
15 changed files with 160 additions and 108 deletions

View File

@ -10,7 +10,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;

View File

@ -7,7 +7,11 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;

View File

@ -5,7 +5,11 @@ import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;

View File

@ -1,15 +1,8 @@
package com.chinaweal.youfool.devops.base.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chinaweal.youfool.devops.base.entity.TaskHandle;
import com.chinaweal.youfool.devops.base.service.ITaskHandleService;
import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.Serializable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
@ -23,5 +16,5 @@ import java.io.Serializable;
@RestController
@RequestMapping("/base/taskHandle")
public class TaskHandleController {
// TODO: 实现任务处理流程相关的REST接口
}

View File

@ -3,6 +3,7 @@ package com.chinaweal.youfool.devops.leaderassign.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskListQuery;
import com.chinaweal.youfool.devops.leaderassign.entity.Assign;
import com.chinaweal.youfool.devops.leaderassign.service.IAssignService;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
@ -12,11 +13,15 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Map;
/**
* <p>
@ -45,8 +50,8 @@ public class AssignController {
@Operation(summary = "2.分页查询领导交办列表")
@PostMapping("/listTask")
public RestResult<IPage<TaskAssignVo>> listTask(@RequestBody Map map) {
IPage<TaskAssignVo> data = iAssignService.listTask(map);
public RestResult<IPage<TaskAssignVo>> listTask(@RequestBody TaskListQuery query) {
IPage<TaskAssignVo> data = iAssignService.listTask(query);
return RestResult.ok(data);
}

View File

@ -0,0 +1,90 @@
package com.chinaweal.youfool.devops.leaderassign.controller.dto;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 任务列表查询参数
*
* @author chinaweal
* @since 2025-08-13
*/
@Schema(description = "任务列表查询参数")
public class TaskListQuery {
@Schema(description = "当前页")
private Integer current;
@Schema(description = "每页大小")
private Integer size;
@Schema(description = "任务标题")
private String title;
@Schema(description = "状态")
private String status;
@Schema(description = "处理人ID")
private String handlerId;
@Schema(description = "创建开始时间")
private String createTimeStart;
@Schema(description = "创建结束时间")
private String createTimeEnd;
public Integer getCurrent() {
return current;
}
public void setCurrent(Integer current) {
this.current = current;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getHandlerId() {
return handlerId;
}
public void setHandlerId(String handlerId) {
this.handlerId = handlerId;
}
public String getCreateTimeStart() {
return createTimeStart;
}
public void setCreateTimeStart(String createTimeStart) {
this.createTimeStart = createTimeStart;
}
public String getCreateTimeEnd() {
return createTimeEnd;
}
public void setCreateTimeEnd(String createTimeEnd) {
this.createTimeEnd = createTimeEnd;
}
}

View File

@ -4,10 +4,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskListQuery;
import com.chinaweal.youfool.devops.leaderassign.entity.Assign;
import org.apache.ibatis.annotations.Param;
import java.util.Map;
/**
* <p>
@ -19,5 +19,5 @@ import java.util.Map;
*/
public interface AssignMapper extends BaseMapper<Assign> {
IPage<TaskAssignVo> listTask(Page page, @Param("map") Map map);
IPage<TaskAssignVo> listTask(Page page, @Param("query") TaskListQuery query);
}

View File

@ -4,9 +4,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskListQuery;
import com.chinaweal.youfool.devops.leaderassign.entity.Assign;
import java.util.Map;
/**
* <p>
@ -32,7 +32,7 @@ public interface IAssignService extends IService<Assign> {
/**
* 获取领导交办待办
*/
IPage<TaskAssignVo> listTask(Map map);
IPage<TaskAssignVo> listTask(TaskListQuery query);
Assign getAssign(String bizId);

View File

@ -15,6 +15,7 @@ import com.chinaweal.youfool.devops.base.service.ITaskHandleService;
import com.chinaweal.youfool.devops.base.service.ITaskListService;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo;
import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskListQuery;
import com.chinaweal.youfool.devops.leaderassign.entity.Assign;
import com.chinaweal.youfool.devops.leaderassign.mapper.AssignMapper;
import com.chinaweal.youfool.devops.leaderassign.service.IAssignService;
@ -35,7 +36,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
@ -131,13 +131,12 @@ public class AssignServiceImpl extends ServiceImpl<AssignMapper, Assign> impleme
}
@Override
public IPage<TaskAssignVo> listTask(Map map) {
Integer current = (Integer) map.getOrDefault("current", 1);
Integer size = (Integer) map.getOrDefault("size", 10);
public IPage<TaskAssignVo> listTask(TaskListQuery query) {
Integer current = query.getCurrent() != null ? query.getCurrent() : 1;
Integer size = query.getSize() != null ? query.getSize() : 10;
Page<TaskAssignVo> page = new Page<>(current, size);
return baseMapper.listTask(page, map);
return baseMapper.listTask(page, query);
}
@Override

View File

@ -14,7 +14,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;

View File

@ -18,7 +18,6 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;

View File

@ -18,7 +18,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;

View File

@ -14,7 +14,12 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalDateTime;

View File

@ -7,11 +7,11 @@ logging:
spring:
datasource:
youfool:
url: jdbc:postgresql://172.22.80.157:5432/devops_gd?currentSchema=public
url: jdbc:postgresql://172.22.80.157:5432/devops_gd?currentSchema=dev
username: devops_gd
password: ChinaWeal@2024
devops:
url: jdbc:postgresql://172.22.80.157:5432/devops_gd?currentSchema=public
url: jdbc:postgresql://172.22.80.157:5432/devops_gd?currentSchema=dev
username: devops_gd
password: ChinaWeal@2024
main:

View File

@ -7,87 +7,23 @@
from task_list t
left join assign a on t.task_id = a.task_id
<where>
<if test="map.sendId !=null and map.sendId != ''">
t.send_id = #{map.sendId}
<if test="query.handlerId !=null and query.handlerId != ''">
t.sign_id = #{query.handlerId}
</if>
<if test="map.signId !=null and map.signId != ''">
and t.sign_id = #{map.signId}
<if test="query.title !=null and query.title != ''">
and t.title like concat(concat('%',#{query.title}),'%')
</if>
<if test="map.bizId !=null and map.bizId != ''">
and t.biz_id like concat(concat('%',#{map.bizId}),'%')
<if test="query.status !=null and query.status != ''">
and t.step = #{query.status}
</if>
<if test="map.title !=null and map.title != ''">
and t.title like concat(concat('%',#{map.title}),'%')
<if test="query.createTimeStart !=null and query.createTimeStart != ''">
and t.launch_time >= to_date(#{query.createTimeStart},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.signName !=null and map.signName != ''">
and t.sign_name like concat(concat('%',#{map.signName}),'%')
</if>
<if test="map.urgency !=null and map.urgency != ''">
and t.urgency = #{map.urgency}
</if>
<if test="map.urgency !=null and map.urgency != ''">
and t.urgency = #{map.urgency}
</if>
<if test="map.step !=null and map.step != ''">
and t.step = #{map.step}
</if>
<if test="map.sendUsername !=null and map.sendUsername != ''">
and t.send_username = #{map.sendUsername}
</if>
<if test="map.org !=null and map.org != ''">
and t.org like concat(#{map.org},'%')
</if>
<if test="map.launchTimeStart!=null">
and t.launch_time >= to_date(#{map.launchTimeStart},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.launchTimeEnd!=null">
and t.launch_time &lt;= to_date(#{map.launchTimeEnd},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.assignTimeStart!=null">
and a.assign_time >= to_date(#{map.assignTimeStart},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.assignTimeEnd!=null">
and a.assign_time &lt;= to_date(#{map.assignTimeEnd},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.handleTimeStart!=null">
and a.handle_time >= to_date(#{map.handleTimeStart},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.handleTimeEnd!=null">
and a.handle_time &lt;= to_date(#{map.handleTimeEnd},'yyyy-mm-dd,hh24:mi:ss')
</if>
<if test="map.steps !=null and map.steps.size > 0">
and t.step in
<foreach item="item" index="index" collection="map.steps"
open="(" separator="," close=")">
#{item}
</foreach>
<if test="query.createTimeEnd !=null and query.createTimeEnd != ''">
and t.launch_time &lt;= to_date(#{query.createTimeEnd},'yyyy-mm-dd,hh24:mi:ss')
</if>
and t.deleted = '0'
</where>
<if test="map.orderField !=null">
order by
<choose>
<when test="map.orderField == 'launch_time'">
t.launch_time
</when>
<when test="map.orderField == 'urgency'">
t.urgency
</when>
<when test="map.orderField == 'step'">
t.step
</when>
<when test="map.orderField == 'sign_name'">
t.sign_name
</when>
</choose>
<choose>
<when test="map.orderSort == 'desc'">
desc
</when>
<otherwise>
ase
</otherwise>
</choose>
</if>
order by t.launch_time desc
</select>
</mapper>