本项目使用两个数据库:
根据FlinkDataSync项目的配置,以下表位于TugboatCommon库:
业务表位于LiandaTugboatMIS库:
只有tugboatcommon和liandatugboatmis这两个库同时存在的表才需要读写分离:
@Service
@DataSource(value = RoutingDataSourceConfig.DataSourceType.COMMON)
public class UserService {
// 使用TugboatCommon库
}
@Service
@DataSource(value = RoutingDataSourceConfig.DataSourceType.MIS)
public class BusinessService {
// 使用LiandaTugboatMIS库
}
以下字段为公共字段,所有表如果存在这些字段,都需要在新增和修改操作中处理:
@Transactional
public UserDTO createUser(UserCreateDTO userCreateDTO) {
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setLoginId(userCreateDTO.getLoginId());
user.setName(userCreateDTO.getName());
// 设置公共字段
String currentUserId = getCurrentUserId();
user.setRecordStatus(1); // 新增默认RecordStatus为1(启用)
user.setCreateUserID(currentUserId); // 创建人为当前登录人
user.setCreateTime(new Date()); // 创建时间为当前时间
user.setModifyUserID(currentUserId); // 修改人为当前登录人
user.setModifyTime(new Date()); // 修改时间为当前时间
user = userRepository.save(user);
return UserDTO.fromEntity(user);
}
/**
* 获取当前登录用户ID
*/
private String getCurrentUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return userDetails.getUsername();
}
return "admin"; // 默认返回admin
}
@Transactional
public UserDTO updateUser(String userId, UserUpdateDTO userUpdateDTO) {
User user = userRepository.findById(userId).orElseThrow(() ->
new RuntimeException("用户不存在"));
user.setLoginId(userUpdateDTO.getLoginId());
user.setName(userUpdateDTO.getName());
// 更新公共字段
String currentUserId = getCurrentUserId();
user.setModifyUserID(currentUserId); // 修改人为当前登录人
user.setModifyTime(new Date()); // 修改时间为当前时间
user = userRepository.save(user);
return UserDTO.fromEntity(user);
}
const addUserForm = reactive({
loginId: '',
name: '',
recordStatus: 1 // 默认设置为1(启用)
})
@Entity
@Table(name = "Sys_User")
public class User {
@Id
@Column(name = "UserID")
private String id;
@Column(name = "LoginID")
private String loginId;
@Column(name = "Name")
private String name;
@Column(name = "Password")
private String password;
@Column(name = "RecordStatus")
private Integer recordStatus;
@Column(name = "CreateUserID")
private String createUserID;
@Column(name = "CreateTime")
private Date createTime;
@Column(name = "ModifyUserID")
private String modifyUserID;
@Column(name = "ModifyTime")
private Date modifyTime;
}
获取Sys_DictionaryItem数据时,必须同时传递DictionaryCode和Value值:
// 错误:只传递Value值
SysDictionaryItem item = sysDictionaryItemRepository.findByValue(1);
// 正确:同时传递DictionaryCode和Value
SysDictionaryItem item = sysDictionaryItemRepository.findByDictionaryCodeAndValue("RecordStatus", 1);
@Repository
public interface SysDictionaryItemRepository extends JpaRepository<SysDictionaryItem, String> {
@Query(value = "SELECT * FROM Sys_DictionaryItem WHERE DictionaryCode = :dictionaryCode AND Value = :value", nativeQuery = true)
SysDictionaryItem findByDictionaryCodeAndValue(@Param("dictionaryCode") String dictionaryCode, @Param("value") Integer value);
@Query(value = "SELECT * FROM Sys_DictionaryItem WHERE DictionaryCode = :dictionaryCode ORDER BY OrderNo", nativeQuery = true)
List<SysDictionaryItem> findByDictionaryCode(@Param("dictionaryCode") String dictionaryCode);
}
@Transactional
public UserDTO createUser(UserCreateDTO userCreateDTO) {
// 重复校验:检查LoginID是否重复
if (userRepository.findByLoginID(userCreateDTO.getLoginId()) != null) {
throw new RuntimeException("账号已存在,请使用其他账号");
}
// 重复校验:检查Name是否重复
if (userRepository.findByName(userCreateDTO.getName()) != null) {
throw new RuntimeException("用户名已存在,请使用其他用户名");
}
// 创建用户...
}
@Transactional
public UserDTO updateUser(String userId, UserUpdateDTO userUpdateDTO) {
User user = userRepository.findById(userId).orElseThrow(() ->
new RuntimeException("用户不存在"));
// 重复校验:检查LoginID是否与其他用户重复
User existingUser = userRepository.findByLoginID(userUpdateDTO.getLoginId());
if (existingUser != null && !existingUser.getId().equals(userId)) {
throw new RuntimeException("账号已存在,请使用其他账号");
}
// 重复校验:检查Name是否与其他用户重复
existingUser = userRepository.findByName(userUpdateDTO.getName());
if (existingUser != null && !existingUser.getId().equals(userId)) {
throw new RuntimeException("用户名已存在,请使用其他用户名");
}
// 更新用户...
}
使用MD5加密密码:
private String md5(String password) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(password.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("密码加密失败", e);
}
}
新增用户时,默认密码为"TIMS123456"的MD5值:
user.setPassword(md5("TIMS123456"));
前端必须显示删除确认对话框:
const deleteUser = async (id) => {
try {
await ElMessageBox.confirm(
'确定要删除该用户吗?删除后用户及其角色关联将被永久删除,不可恢复。',
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
await request.delete(`/user/delete/${id}`)
ElMessage.success('删除成功')
getUsers()
} catch (error) {
if (error !== 'cancel') {
console.error('删除用户失败:', error)
ElMessage.error('删除用户失败')
}
}
}
删除主表数据时,必须先删除关联表数据:
@Transactional
public void deleteUsers(List<String> userIds) {
for (String userId : userIds) {
// 先删除关联表数据
sysUserRoleRepository.deleteByUserId(userId);
// 再删除主表数据
userRepository.deleteById(userId);
}
}
对于需要动态拼接SQL的查询,使用JdbcTemplate:
@Autowired
@Qualifier("writeJdbcTemplate")
private JdbcTemplate writeJdbcTemplate;
public List<User> queryUsers(UserQuery query) {
StringBuilder sql = new StringBuilder("SELECT * FROM Sys_User WHERE 1=1");
List<Object> params = new ArrayList<>();
if (query.getLoginId() != null && !query.getLoginId().isEmpty()) {
sql.append(" AND LoginID LIKE ?");
params.add("%" + query.getLoginId() + "%");
}
if (query.getName() != null && !query.getName().isEmpty()) {
sql.append(" AND Name LIKE ?");
params.add("%" + query.getName() + "%");
}
return writeJdbcTemplate.query(sql.toString(), params.toArray(), new UserRowMapper());
}
// 错误:使用+号拼接字符串
@Query(value = "SELECT * FROM Sys_User WHERE LoginID LIKE '%' + :loginID + '%'", nativeQuery = true)
// 正确:使用CONCAT函数
@Query(value = "SELECT * FROM Sys_User WHERE LoginID LIKE CONCAT('%', :loginID, '%')", nativeQuery = true)
User findByLoginIDLike(@Param("loginID") String loginID);
使用Pageable处理排序,不要在SQL中写死ORDER BY:
public Page<User> queryUsers(UserQuery query, Pageable pageable) {
Sort sort = pageable.getSort();
if (query.getSortBy() != null && query.getSortOrder() != null) {
sort = Sort.by(
"asc".equalsIgnoreCase(query.getSortOrder()) ? Sort.Direction.ASC : Sort.Direction.DESC,
query.getSortBy()
);
}
return userRepository.findAll(pageable.withSort(sort));
}
使用RuntimeException抛出业务异常:
if (userRepository.findByLoginID(userCreateDTO.getLoginId()) != null) {
throw new RuntimeException("账号已存在,请使用其他账号");
}
try {
await request.post('/user/create', data)
ElMessage.success('操作成功')
} catch (error) {
console.error('操作失败:', error)
ElMessage.error(error.response?.data?.message || '操作失败,请稍后重试')
}
所有涉及多个数据库操作的方法都必须添加@Transactional注解:
@Transactional
public UserDTO createUser(UserCreateDTO userCreateDTO) {
// 创建用户
User user = userRepository.save(user);
// 创建用户角色关联
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getId());
userRole.setRoleId(userCreateDTO.getRoleId());
sysUserRoleRepository.save(userRole);
return UserDTO.fromEntity(user);
}
查询方法可以使用@Transactional(readOnly = true):
@Transactional(readOnly = true)
public Page<User> queryUsers(UserQuery query, Pageable pageable) {
return userRepository.findAll(pageable);
}
public Page<User> queryUsers(UserQuery query, Pageable pageable) {
return userRepository.findAll(pageable);
}
const getUsers = async () => {
const response = await request.get('/user/list', {
params: {
page: currentPage.value,
pageSize: pageSize.value,
sortBy: sortMap.value.sortBy,
sortOrder: sortMap.value.sortOrder
}
})
userList.value = response.data.content
total.value = response.data.totalElements
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public UserDTO createUser(UserCreateDTO userCreateDTO) {
logger.info("开始创建用户,账号:{}", userCreateDTO.getLoginId());
try {
// 创建用户逻辑
logger.info("用户创建成功,ID:{}", user.getId());
return UserDTO.fromEntity(user);
} catch (Exception e) {
logger.error("用户创建失败", e);
throw new RuntimeException("用户创建失败", e);
}
}
}