feat(web): 新增 BaseController 基类并优化代码生成模板

- 添加 BaseController 基类,包含常用方法如获取登录用户、租户ID等
- 实现统一的 ApiResult 返回结果处理方法
- 添加请求参数空字符串转 null 的处理逻辑- 新增方法参数类型转换异常的统一处理机制
- 更新代码生成器模板,将 ID 类型从 Integer 改为 Long
- 修改代码生成器配置,使用新的 BaseController 替代 SimpleBaseController
- 优化 HTTP 请求头获取逻辑,支持大小写兼容的 AppId 获取方式
This commit is contained in:
2025-10-16 20:29:33 +08:00
parent 97041ad515
commit ed6bb2772f
6 changed files with 225 additions and 56 deletions

View File

@@ -0,0 +1,221 @@
package com.gxwebsoft.common.core.web;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.common.core.Constants;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Controller基类
*
* @author WebSoft
* @since 2017-06-10 10:10:19
*/
public class BaseController {
@Resource
private HttpServletRequest request;
@Resource
// private RedisUtil redisUtil;
/**
* 获取当前登录的user
*
* @return User
*/
// public User getLoginUser() {
// try {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// if (authentication != null) {
// Object object = authentication.getPrincipal();
// if (object instanceof User) {
// return (User) object;
// }
// }
// } catch (Exception e) {
// System.out.println(e.getMessage());
// }
// return null;
// }
/**
* 获取当前登录的userId
*
* @return userId
*/
public Integer getLoginUserId() {
return null;
}
/**
* 获取当前登录的tenantId
*
* @return tenantId
*/
public Integer getTenantId() {
String tenantId;
// 2 从请求头拿ID
tenantId = request.getHeader("tenantId");
if(StrUtil.isNotBlank(tenantId)){
return Integer.valueOf(tenantId);
}
return null;
}
/**
* 返回成功
*
* @return ApiResult
*/
public ApiResult<?> success() {
return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG);
}
/**
* 返回成功
*
* @param message 状态信息
* @return ApiResult
*/
public ApiResult<?> success(String message) {
return success().setMessage(message);
}
/**
* 返回成功
*
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> success(T data) {
return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG, data);
}
/**
* 返回成功
*
* @param message 状态信息
* @return ApiResult
*/
public <T> ApiResult<T> success(String message, T data) {
return success(data).setMessage(message);
}
/**
* 返回分页查询数据
*
* @param list 当前页数据
* @param count 总数量
* @return ApiResult
*/
public <T> ApiResult<PageResult<T>> success(List<T> list, Long count) {
return success(new PageResult<>(list, count));
}
/**
* 返回分页查询数据
*
* @param iPage IPage
* @return ApiResult
*/
public <T> ApiResult<PageResult<T>> success(IPage<T> iPage) {
return success(iPage.getRecords(), iPage.getTotal());
}
/**
* 返回失败
*
* @return ApiResult
*/
public ApiResult<?> fail() {
return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG);
}
/**
* 返回失败
*
* @param message 状态信息
* @return ApiResult
*/
public ApiResult<?> fail(String message) {
return fail().setMessage(message);
}
/**
* 返回失败
*
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> fail(T data) {
return fail(Constants.RESULT_ERROR_MSG, data);
}
/**
* 返回失败
*
* @param message 状态信息
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> fail(String message, T data) {
return new ApiResult<>(Constants.RESULT_ERROR_CODE, message, data);
}
/**
* 请求参数的空字符串转为null
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
// 自定义函数
public String getAuthorization(){
return request.getHeader("Authorization");
}
public String getAppId() {
// 兼容小写
if(request.getHeader("appid") != null){
return request.getHeader("appid");
}
return request.getHeader("AppId");
}
/**
* 处理方法参数类型转换异常
* 主要处理URL路径参数中传入"NaN"等无法转换为Integer的情况
*
* @param ex 方法参数类型不匹配异常
* @return ApiResult
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ApiResult<?> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) {
String parameterName = ex.getName();
Object value = ex.getValue();
Class<?> requiredType = ex.getRequiredType();
// 记录错误日志
System.err.println("参数类型转换异常: 参数名=" + parameterName +
", 传入值=" + value +
", 期望类型=" + (requiredType != null ? requiredType.getSimpleName() : "unknown"));
// 如果是ID参数且传入的是"NaN",返回友好的错误信息
if ("id".equals(parameterName) && "NaN".equals(String.valueOf(value))) {
return fail("无效的ID参数请检查传入的ID值");
}
// 其他类型转换错误的通用处理
return fail("参数格式错误: " + parameterName + " 的值 '" + value + "' 无法转换为 " +
(requiredType != null ? requiredType.getSimpleName() : "目标类型"));
}
}

View File

@@ -1,52 +0,0 @@
package com.gxwebsoft.common.core.web;
import org.springframework.web.bind.annotation.RestController;
/**
* 简化版控制器基类,用于代码生成
* Created by WebSoft on 2019-10-29 15:55
*/
@RestController
public class SimpleBaseController {
/**
* 响应成功结果
*
* @param data 数据内容
* @param <T> 数据类型
* @return 响应结果
*/
protected <T> ApiResult<T> success(T data) {
return new ApiResult<T>(0, "操作成功", data);
}
/**
* 响应成功结果
*
* @return 响应结果
*/
protected ApiResult<String> success(String message) {
return new ApiResult<String>(0, message, null);
}
/**
* 响应失败结果
*
* @param message 错误信息
* @return 响应结果
*/
protected ApiResult<String> fail(String message) {
return new ApiResult<String>(1, message, null);
}
/**
* 响应失败结果
*
* @param code 错误码
* @param message 错误信息
* @return 响应结果
*/
protected ApiResult<String> fail(int code, String message) {
return new ApiResult<String>(code, message, null);
}
}

View File

@@ -135,7 +135,7 @@ public class ClinicGenerator {
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setInclude(TABLE_NAMES);
strategy.setTablePrefix(TABLE_PREFIX);
strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.SimpleBaseController");
strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.BaseController");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);

View File

@@ -106,7 +106,7 @@ public class ${table.controllerName} {
@PreAuthorize("hasAuthority('${authPre}:list')")
@Operation(summary = "根据id查询${table.comment!}")
@GetMapping("/{id}")
public ApiResult<${entity}> get(@PathVariable("id") Integer id) {
public ApiResult<${entity}> get(@PathVariable("id") Long id) {
// 使用关联查询
return success(${serviceIns}.getByIdRel(id));
}

View File

@@ -49,7 +49,7 @@ public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
* @param ${idPropertyName!} ${idComment!}
* @return ${entity}
*/
${entity} getByIdRel(Integer ${idPropertyName!});
${entity} getByIdRel(Long ${idPropertyName!});
}
<% } %>

View File

@@ -52,7 +52,7 @@ public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.m
}
@Override
public ${entity} getByIdRel(Integer ${idPropertyName!}) {
public ${entity} getByIdRel(Long ${idPropertyName!}) {
${entity}Param param = new ${entity}Param();
param.set${idCapitalName!}(${idPropertyName!});
return param.getOne(baseMapper.selectListRel(param));