feat: add department name uniqueness check and corresponding error message

This commit is contained in:
siujamo
2026-03-24 15:49:48 +08:00
parent 6f29904349
commit 9d2fc024ea
8 changed files with 68 additions and 46 deletions
@@ -44,40 +44,13 @@ public class BizException extends RuntimeException {
private final String messageCode;
private final Object[] messageArgs;
/**
* Constructs a new business exception with the specified HTTP status and message.
*
* @param message the detailed error message explaining the business logic violation
*/
public BizException(String message) {
super(message);
this.status = HttpStatus.INTERNAL_SERVER_ERROR;
this.messageCode = null;
this.messageArgs = new Object[0];
}
/**
* Constructs a new business exception with the specified HTTP status and message.
*
* @param status the HTTP status code to associate with this exception
* @param message the detailed error message explaining the business logic violation
*/
public BizException(HttpStatus status, String message) {
super(message);
this.status = status;
this.messageCode = null;
this.messageArgs = new Object[0];
}
public BizException(String messageCode, Object... messageArgs) {
super(messageCode);
this.status = HttpStatus.INTERNAL_SERVER_ERROR;
this.messageCode = messageCode;
this.messageArgs = messageArgs == null ? new Object[0] : messageArgs;
}
public BizException(HttpStatus status, String messageCode, Object... messageArgs) {
super(messageCode);
this.status = status;
this.messageCode = messageCode;
this.messageArgs = messageArgs == null ? new Object[0] : messageArgs;
@@ -3,6 +3,8 @@ package com.onixbyte.helix.manager;
import com.onixbyte.helix.domain.entity.Department;
import com.onixbyte.helix.exception.BizException;
import com.onixbyte.helix.repository.DepartmentRepository;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -68,4 +70,8 @@ public class DepartmentManager {
departmentToEdit.setUpdatedAt(updatedAt);
return departmentToEdit;
}
public boolean existsByName(String name) {
return departmentRepository.existsByName(name);
}
}
@@ -15,4 +15,6 @@ public interface DepartmentRepository extends JpaRepository<Department, Long> {
or d.parentId = :parentId
""")
Integer findMaxSort(Long parentId);
boolean existsByName(String name);
}
@@ -4,10 +4,13 @@ import com.onixbyte.helix.domain.common.TreeNode;
import com.onixbyte.helix.domain.entity.Department;
import com.onixbyte.helix.domain.web.request.DepartmentRequest;
import com.onixbyte.helix.enumeration.Status;
import com.onixbyte.helix.exception.BizException;
import com.onixbyte.helix.manager.DepartmentManager;
import com.onixbyte.helix.shared.MessageName;
import com.onixbyte.helix.utils.TreeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -38,6 +41,10 @@ public class DepartmentService {
public Department addDepartment(DepartmentRequest request) {
var createdAt = LocalDateTime.now();
if (departmentManager.existsByName(request.name())) {
throw new BizException(HttpStatus.CONFLICT, MessageName.REQUEST_CREATE_DEPARTMENT_NAME_DUPLICATED);
}
var parentId = request.parentId();
var sort = Optional.ofNullable(request.sort())
.orElseGet(() -> departmentManager.getNextSort(parentId));
@@ -79,4 +79,6 @@ public class MessageName {
public static final String REQUEST_QUERY_ROLE_STATUS_INVALID = "request.query-role.status.invalid";
public static final String REQUEST_QUERY_USER_STATUS_INVALID = "request.query-user.status.invalid";
public static final String REQUEST_CREATE_DEPARTMENT_NAME_DUPLICATED = "request.create-department.name-duplicated";
}
+48 -18
View File
@@ -19,28 +19,58 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
tree.multiple-roots=
user.not-found=User with ID [{0}] not found.
security.context-user-not-found=Cannot retrieve user information from security context.
role.not-exists=Role does not exist in database.
captcha.generate-failed=
auth.provider.password-not-configured=Username or password is incorrect.
auth.provider.bad-credentials=Username or password is incorrect.
auth.provider.failed=Authentication failed, please try again later.
auth.login.failed=Cannot perform login due to server error.
auth.login.captcha-incorrect=Captcha is incorrect.
auth.login.captcha-not-found=Captcha not found.
authority.not-found=Authority with ID [{0}] not found.
authority.code-used=Authority code [{0}] is already in use.
asset.upload-failed=Failed to upload file: {0}
asset.delete-forbidden=You are not able to delete an asset that is not uploaded by you.
asset.invalid-prefix=Prefix must not be empty and must not start with '/' or '..'.
asset.not-empty = File cannot be empty.
asset.invalid-prefix = Prefix must not be empty and must not start with '/' or '..'.
asset.delete-forbidden = You are not able to delete an asset that is not uploaded by you.
asset.upload-failed = Failed to upload file: {0}
authority.deleted = Authority [{0}] deleted.
authority.code-used = Authority code [{0}] is already in use.
authority.not-found = Authority with ID [{0}] not found.
auth.login.captcha-not-found = Captcha not found.
auth.login.captcha-incorrect = Captcha is incorrect.
auth.login.failed = Cannot perform login due to server error.
auth.provider.failed = Authentication failed, please try again later.
auth.provider.bad-credentials = Username or password is incorrect.
auth.provider.password-not-configured=Username or password is incorrect.
captcha.generate-failed = Unable to generate captcha image.
role.not-exists=Name of the authority cannot be null.
role.not-found = Role with ID {0} not found.
role.deleted = Role [{0}] deleted.
user.password-reset-success = Password has been reset.
user.deleted = User [{0}] deleted.
role.not-found=Role with ID {0} not found.
role.deleted=Role [{0}] deleted.
user.not-found = User with ID [{0}] not found.
security.context-user-not-found = Cannot retrieve user information from security context.
tree.multiple-roots = Multiple root items found in given values.
request.add-user.username.not-empty = Username cannot be empty.
request.add-user.password.not-empty = Password cannot be empty.
request.add-user.full-name.not-empty = Full name cannot be empty.
request.authority.code.not-editable = Code cannot be edited.
request.authority.code.not-null = Code cannot be null.
request.authority.name.not-null = Name of the authority cannot be null.
request.department.name.not-null = Name of the department should not be null.
request.edit-role.id.not-null = Role ID cannot be null.
request.edit-role.status.invalid = Status can only be ACTIVE or INACTIVE.
request.edit-user.id.not-null = User ID cannot be null.
request.edit-user.id.positive = User ID must be positive.
request.reset-password.password.not-empty = Password cannot be empty.
request.role.name.not-empty = Name of the role cannot be empty.
request.role.code.not-empty = Code of the role cannot be empty.
request.role.sort.not-null = Sort number cannot be null.
request.query-role.status.invalid = Status can only be ACTIVE or INACTIVE.
request.query-user.status.invalid = Status can only be ACTIVE, INACTIVE, or LOCKED.
request.create-department.name-duplicated=Name of the department already exists.
@@ -74,3 +74,4 @@ request.role.sort.not-null = Sort number cannot be null.
request.query-role.status.invalid = Status can only be ACTIVE or INACTIVE.
request.query-user.status.invalid = Status can only be ACTIVE, INACTIVE, or LOCKED.
request.create-department.name-duplicated=Name of the department already exists.
@@ -74,3 +74,4 @@ request.role.sort.not-null = 排序编号不能为空。
request.query-role.status.invalid = 状态只能是 ACTIVE 或 INACTIVE。
request.query-user.status.invalid = 状态只能是 ACTIVE、INACTIVE 或 LOCKED。
request.create-department.name-duplicated=部门名称已存在。