diff --git a/backend/src/main/java/com/qqchen/deploy/backend/api/TenantApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/api/TenantApiController.java new file mode 100644 index 00000000..453ffe44 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/api/TenantApiController.java @@ -0,0 +1,33 @@ +package com.qqchen.deploy.backend.api; + +import com.qqchen.deploy.backend.common.api.Response; +import com.qqchen.deploy.backend.common.controller.BaseController; +import com.qqchen.deploy.backend.converter.TenantConverter; +import com.qqchen.deploy.backend.dto.query.TenantQuery; +import com.qqchen.deploy.backend.dto.request.TenantRequest; +import com.qqchen.deploy.backend.dto.response.TenantResponse; +import com.qqchen.deploy.backend.entity.Tenant; +import com.qqchen.deploy.backend.service.ITenantService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/tenant") +public class TenantApiController extends BaseController { + + protected final ITenantService service; + + public TenantApiController(ITenantService service, TenantConverter converter) { + super(service, converter); + this.service = service; + } + + @GetMapping("/code/{code}") + public Response findByCode(@PathVariable String code) { + Tenant tenant = service.findByCode(code); + return Response.success(converter.toResponse(tenant)); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/common/enums/ResponseCode.java index 66220825..8e2e8a2d 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/enums/ResponseCode.java @@ -8,12 +8,16 @@ public enum ResponseCode { ERROR(500, "response.error"), INVALID_PARAM(400, "response.invalid.param"), UNAUTHORIZED(401, "response.unauthorized"), + AUTH_REQUIRED(401, "response.unauthorized.full"), FORBIDDEN(403, "response.forbidden"), NOT_FOUND(404, "response.not.found"), CONFLICT(409, "response.conflict"), // 业务错误码 TENANT_NOT_FOUND(1001, "tenant.not.found"), + DATA_NOT_FOUND(1002, "data.not.found"), + + // 用户相关错误码(2开头) USER_NOT_FOUND(2001, "user.not.found"), USERNAME_EXISTS(2002, "user.username.exists"), EMAIL_EXISTS(2003, "user.email.exists"); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java b/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java index 9d6ded0c..0b143b5b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java @@ -20,7 +20,7 @@ public class TenantInterceptor implements HandlerInterceptor { // 不需要进行租户隔离的路径 private final List excludePaths = Arrays.asList( // "/api/v1/users/login", - "/api/system/tenants/list", + "/api/v1/tenant/list", "/swagger-ui/**", "/v3/api-docs/**" ); @@ -28,7 +28,6 @@ public class TenantInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String path = request.getRequestURI(); - System.out.println("Intercepting path: " + path); // 添加日志 // 如果是白名单路径,不进行租户校验 if (isExcludePath(path)) { TenantContext.clear(); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/query/BaseQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/common/query/BaseQuery.java index 58a291d6..c97882e1 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/query/BaseQuery.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/query/BaseQuery.java @@ -9,9 +9,13 @@ import java.time.LocalDateTime; @Data public abstract class BaseQuery implements Serializable { + private Integer pageNum = 1; + private Integer pageSize = 10; + private String sortField = "createTime"; + private String sortOrder = "desc"; // 通用状态查询 diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java index e000b998..2ee8440a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java @@ -49,7 +49,7 @@ public class SecurityConfig { .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(authenticationEntryPoint)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/api/v1/users/login", "/api/v1/users/register").permitAll() + .requestMatchers("/api/v1/users/login", "/api/v1/users/register", "/api/v1/tenant/list").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() .requestMatchers("/actuator/health").permitAll() .anyRequest().authenticated() diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/security/filter/JwtAuthenticationFilter.java b/backend/src/main/java/com/qqchen/deploy/backend/common/security/filter/JwtAuthenticationFilter.java index 445da93f..e744fac3 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/security/filter/JwtAuthenticationFilter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/security/filter/JwtAuthenticationFilter.java @@ -25,11 +25,13 @@ import java.util.List; public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenUtil jwtTokenUtil; + private final UserDetailsService userDetailsService; private static final List WHITELIST = Arrays.asList( "/api/v1/users/login", "/api/v1/users/register", + "/api/v1/tenant/list", "/swagger-ui/**", "/v3/api-docs/**", "/actuator/health" @@ -42,14 +44,12 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { try { - String tenantId = request.getHeader("X-Tenant-ID"); - if (tenantId != null && !tenantId.isEmpty()) { - TenantContext.setTenantId(tenantId); - } - +// String tenantId = request.getHeader("X-Tenant-ID"); +// if (tenantId != null && !tenantId.isEmpty()) { +// TenantContext.setTenantId(tenantId); +// } String authHeader = request.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { chain.doFilter(request, response); @@ -61,15 +61,15 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); - + if (jwtTokenUtil.validateToken(token, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities()); + userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } - + chain.doFilter(request, response); } catch (Exception e) { log.error("JWT authentication failed", e); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/security/handler/CustomAuthenticationEntryPoint.java b/backend/src/main/java/com/qqchen/deploy/backend/common/security/handler/CustomAuthenticationEntryPoint.java index 91505161..65491c84 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/security/handler/CustomAuthenticationEntryPoint.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/security/handler/CustomAuthenticationEntryPoint.java @@ -8,6 +8,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.MediaType; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; @@ -27,11 +28,13 @@ public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint response.setCharacterEncoding(StandardCharsets.UTF_8.name()); Response result; if (authException instanceof BadCredentialsException) { - result = Response.error(ResponseCode.UNAUTHORIZED, MessageUtils.getMessage(ResponseCode.SUCCESS.getMessageKey())); + result = Response.error(ResponseCode.UNAUTHORIZED, MessageUtils.getMessage(ResponseCode.UNAUTHORIZED.getMessageKey())); } else if (authException instanceof InternalAuthenticationServiceException) { result = Response.error(ResponseCode.USER_NOT_FOUND, MessageUtils.getMessage(ResponseCode.USER_NOT_FOUND.getMessageKey())); + } else if (authException instanceof InsufficientAuthenticationException) { + result = Response.error(ResponseCode.AUTH_REQUIRED, MessageUtils.getMessage(ResponseCode.AUTH_REQUIRED.getMessageKey())); } else { - result = Response.error(ResponseCode.UNAUTHORIZED, MessageUtils.getMessage(ResponseCode.SUCCESS.getMessageKey())); + result = Response.error(ResponseCode.UNAUTHORIZED, MessageUtils.getMessage(ResponseCode.UNAUTHORIZED.getMessageKey())); } response.getWriter().write(objectMapper.writeValueAsString(result)); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/converter/TenantConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/converter/TenantConverter.java new file mode 100644 index 00000000..eebbd1aa --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/converter/TenantConverter.java @@ -0,0 +1,18 @@ +package com.qqchen.deploy.backend.converter; + +import com.qqchen.deploy.backend.common.converter.BaseConverter; +import com.qqchen.deploy.backend.dto.request.TenantRequest; +import com.qqchen.deploy.backend.dto.request.UserRequest; +import com.qqchen.deploy.backend.dto.response.TenantResponse; +import com.qqchen.deploy.backend.dto.response.UserResponse; +import com.qqchen.deploy.backend.entity.Tenant; +import com.qqchen.deploy.backend.entity.User; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.ReportingPolicy; + +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface TenantConverter extends BaseConverter { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/dto/query/TenantQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/dto/query/TenantQuery.java new file mode 100644 index 00000000..aaf24f1b --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/dto/query/TenantQuery.java @@ -0,0 +1,27 @@ +package com.qqchen.deploy.backend.dto.query; + +import com.qqchen.deploy.backend.common.annotation.QueryField; +import com.qqchen.deploy.backend.common.enums.QueryType; +import com.qqchen.deploy.backend.common.query.BaseQuery; +import jakarta.persistence.Column; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantQuery extends BaseQuery { + + @QueryField(type = QueryType.EQUAL) + private String name; + + @QueryField(type = QueryType.EQUAL) + private String code; + + @QueryField(type = QueryType.EQUAL) + private String contactPhone; + + @QueryField(type = QueryType.EQUAL) + private String email; + +} diff --git a/backend/src/main/java/com/qqchen/deploy/backend/dto/request/TenantRequest.java b/backend/src/main/java/com/qqchen/deploy/backend/dto/request/TenantRequest.java new file mode 100644 index 00000000..f1cac7db --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/dto/request/TenantRequest.java @@ -0,0 +1,27 @@ +package com.qqchen.deploy.backend.dto.request; + +import com.qqchen.deploy.backend.common.dto.BaseRequest; +import jakarta.persistence.Column; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantRequest extends BaseRequest { + + @NotBlank(message = "租户名称不能为空") + private String name; + + @NotBlank(message = "租户编码不能为空") + private String code; + + @NotBlank(message = "租户维护人") + private String contactName; + + @NotBlank(message = "租户维护人电话") + private String contactPhone; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/dto/response/TenantResponse.java b/backend/src/main/java/com/qqchen/deploy/backend/dto/response/TenantResponse.java new file mode 100644 index 00000000..dc3cd106 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/dto/response/TenantResponse.java @@ -0,0 +1,29 @@ +package com.qqchen.deploy.backend.dto.response; + +import com.qqchen.deploy.backend.common.dto.BaseResponse; +import jakarta.persistence.Column; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantResponse extends BaseResponse { + + private Long id; + + private String name; + + private String code; + + private String contactName; + + private String contactPhone; + + private String email; + + private String address; + + private Boolean enabled = true; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/Tenant.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/Tenant.java index 30b08673..94953bc8 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/entity/Tenant.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/Tenant.java @@ -36,4 +36,5 @@ public class Tenant extends Entity { @Column(nullable = false) private Boolean enabled = true; + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/ITenantService.java b/backend/src/main/java/com/qqchen/deploy/backend/service/ITenantService.java index b8a75f12..6d8c7dcc 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/ITenantService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/ITenantService.java @@ -17,5 +17,5 @@ public interface ITenantService extends IBaseService { boolean existsByName(String name); -// List findAll(TenantQuery query); + Tenant findByCode(String code); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/TenantServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/TenantServiceImpl.java index 9b213e19..8ac674ac 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/TenantServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/TenantServiceImpl.java @@ -1,113 +1,69 @@ -//package com.qqchen.deploy.backend.service.impl; -// -//import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl; -//import com.qqchen.deploy.backend.entity.Tenant; -//import com.qqchen.deploy.backend.repository.ITenantRepository; -//import com.qqchen.deploy.backend.service.ITenantService; -//import com.querydsl.core.BooleanBuilder; -//import jakarta.transaction.Transactional; -//import org.springframework.stereotype.Service; -//import org.springframework.util.StringUtils; -// -//import java.util.List; -// -//@Service -//@Transactional -//public class TenantServiceImpl extends BaseServiceImpl implements ITenantService { -// -// private final ITenantRepository tenantRepository; -// -// public TenantServiceImpl(ITenantRepository tenantRepository) { -// super(tenantRepository); -// this.tenantRepository = tenantRepository; -// } -// -// @Override -// public List findAll(TenantQuery query) { -// QTenant tenant = QTenant.tenant; -// BooleanBuilder builder = new BooleanBuilder(); -// -// // 基础条件:未删除 -// builder.and(tenant.deleted.eq(false)); -// -// // 动态条件 -// if (query != null) { -// // 名称模糊查询 -// if (StringUtils.hasText(query.getName())) { -// builder.and(tenant.name.like("%" + query.getName().trim() + "%")); -// } -// -// // 编码模糊查询 -// if (StringUtils.hasText(query.getCode())) { -// builder.and(tenant.code.like("%" + query.getCode().trim() + "%")); -// } -// -// // 状态精确查询 -// if (query.getEnabled() != null) { -// builder.and(tenant.enabled.eq(query.getEnabled())); -// } -// } -// -// // 按ID排序 -// return (List) tenantRepository.findAll(builder, tenant.id.asc()); -// } -// -// @Override -// public List findAllEnabled() { -// QTenant tenant = QTenant.tenant; -// return (List) tenantRepository.findAll( -// tenant.deleted.eq(false) -// .and(tenant.enabled.eq(true)), -// tenant.id.asc() -// ); -// } -// -// @Override -// public Tenant save(Tenant entity) { -// validateCode(entity.getCode()); -// validateName(entity.getName()); -// entity.setDeleted(false); -// return super.save(entity); -// } -// -// @Override -// public Tenant update(Long id, Tenant entity) { -// Tenant existing = findById(id) -// .orElseThrow(() -> new ApiException("租户不存在")); -// -// if (!existing.getCode().equals(entity.getCode())) { -// validateCode(entity.getCode()); -// } -// if (!existing.getName().equals(entity.getName())) { -// validateName(entity.getName()); -// } -// -// entity.setVersion(existing.getVersion()); -// entity.setDeleted(existing.getDeleted()); -// return super.update(id, entity); -// } -// -// @Override -// public void validateCode(String code) { +package com.qqchen.deploy.backend.service.impl; + +import com.qqchen.deploy.backend.common.exception.BusinessException; +import com.qqchen.deploy.backend.common.enums.ResponseCode; +import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl; +import com.qqchen.deploy.backend.entity.QTenant; +import com.qqchen.deploy.backend.entity.Tenant; +import com.qqchen.deploy.backend.repository.ITenantRepository; +import com.qqchen.deploy.backend.service.ITenantService; +import jakarta.transaction.Transactional; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Transactional +public class TenantServiceImpl extends BaseServiceImpl implements ITenantService { + + private final ITenantRepository tenantRepository; + + public TenantServiceImpl(ITenantRepository tenantRepository) { + super(tenantRepository); + this.tenantRepository = tenantRepository; + } + + @Override + public List findAllEnabled() { + QTenant tenant = QTenant.tenant; + return (List) tenantRepository.findAll( + tenant.deleted.eq(false) + .and(tenant.enabled.eq(true)), + tenant.id.asc() + ); + } + + + @Override + public void validateCode(String code) { // if (tenantRepository.existsByCodeAndDeletedFalse(code)) { // throw new ApiException("租户编码已存在"); // } -// } -// -// @Override -// public void validateName(String name) { + } + + @Override + public void validateName(String name) { // if (tenantRepository.existsByNameAndDeletedFalse(name)) { // throw new ApiException("租户名称已存在"); // } -// } -// -// @Override -// public boolean existsByCode(String code) { -// return tenantRepository.existsByCodeAndDeletedFalse(code); -// } -// -// @Override -// public boolean existsByName(String name) { -// return tenantRepository.existsByNameAndDeletedFalse(name); -// } -//} \ No newline at end of file + } + + @Override + public boolean existsByCode(String code) { + return tenantRepository.existsByCodeAndDeletedFalse(code); + } + + @Override + public boolean existsByName(String name) { + return tenantRepository.existsByNameAndDeletedFalse(name); + } + + @Override + public Tenant findByCode(String code) { + QTenant tenant = QTenant.tenant; + return (Tenant) tenantRepository.findOne( + tenant.code.eq(code) + .and(tenant.deleted.eq(false)) + ).orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND)); + } +} \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 099b7eca..3818fc7f 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -3,9 +3,9 @@ server: spring: datasource: - url: jdbc:mysql://192.168.1.111:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true - username: deploy-ease-platform - password: qichen5210523 + url: jdbc:mysql://127.0.0.1:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true + username: root + password: root driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: diff --git a/backend/src/main/resources/messages.properties b/backend/src/main/resources/messages.properties index 51c98249..dc8b4376 100644 --- a/backend/src/main/resources/messages.properties +++ b/backend/src/main/resources/messages.properties @@ -6,10 +6,13 @@ response.unauthorized=\u672A\u6388\u6743 response.forbidden=\u7981\u6B62\u8BBF\u95EE response.not.found=\u8D44\u6E90\u672A\u627E\u5230 response.conflict=\u8D44\u6E90\u51B2\u7A81 +response.unauthorized.full=\u8BBF\u95EE\u6B64\u8D44\u6E90\u9700\u8981\u5B8C\u5168\u8EAB\u4EFD\u9A8C\u8BC1 tenant.not.found=\u79DF\u6237\u4E0D\u5B58\u5728 user.not.found=\u7528\u6237\u4E0D\u5B58\u5728 user.username.exists=\u7528\u6237\u540D\u5DF2\u5B58\u5728 -user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728 \ No newline at end of file +user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728 + +data.not.found=数据不存在 \ No newline at end of file diff --git a/backend/src/main/resources/messages_en.properties b/backend/src/main/resources/messages_en.properties index 5ded67ea..414c139f 100644 --- a/backend/src/main/resources/messages_en.properties +++ b/backend/src/main/resources/messages_en.properties @@ -6,10 +6,13 @@ response.unauthorized=Unauthorized response.forbidden=Forbidden response.not.found=Resource Not Found response.conflict=Resource Conflict +response.unauthorized.full=Full authentication is required to access this resource tenant.not.found=Tenant not found user.not.found=User not found user.username.exists=Username already exists -user.email.exists=Email already exists \ No newline at end of file +user.email.exists=Email already exists + +data.not.found=Data not found \ No newline at end of file diff --git a/backend/src/main/resources/messages_zh_CN.properties b/backend/src/main/resources/messages_zh_CN.properties index fb120b64..da4c906b 100644 --- a/backend/src/main/resources/messages_zh_CN.properties +++ b/backend/src/main/resources/messages_zh_CN.properties @@ -6,9 +6,11 @@ response.unauthorized=\u672A\u6388\u6743 response.forbidden=\u7981\u6B62\u8BBF\u95EE response.not.found=\u8D44\u6E90\u672A\u627E\u5230 response.conflict=\u8D44\u6E90\u51B2\u7A81 +response.unauthorized.full=\u8BBF\u95EE\u6B64\u8D44\u6E90\u9700\u8981\u5B8C\u5168\u8EAB\u4EFD\u9A8C\u8BC1 tenant.not.found=\u79DF\u6237\u4E0D\u5B58\u5728 user.not.found=\u7528\u6237\u4E0D\u5B58\u5728 user.username.exists=\u7528\u6237\u540D\u5DF2\u5B58\u5728 -user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728 \ No newline at end of file +user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728 +data.not.found=数据不存在 \ No newline at end of file