Let’s Talk about Some of the Chaos You’ll Find on Java Servers in Startups

The Controller Base Class and Service Base Class Are Used

Introduction to Base Classes

/** Controller Base Classes */
public class BaseController {
/** Injection services related */
/** User Service */
@Autowired
protected UserService userService;
...
/** Static constant correlation */
/** Phone number mode */
protected static final String PHONE_PATTERN = "/^[1]([3-9])[0-9]{9}$/";
...
/** Static function related */
/** Verify phone number */
protected static vaildPhone(String phone) {...}
...
}
/** Service Base Classes */
public class BaseService {
/** Injection DAO related */
/** User DAO */
@Autowired
protected UserDAO userDAO;
...
/** Injection services related */
/** SMS service */
@Autowired
protected SmsService smsService;
...

/** Injection parameters related */
/** system name */
@Value("${example.systemName}")
protected String systemName;
...
/** Injection constant related */
/** super user ID */
protected static final long SUPPER_USER_ID = 0L;
...
/** Service function related */
/** Get user function */
protected UserDO getUser(Long userId) {...}
...
/** Static function related */
/** Get user name */
protected static String getUserName(UserDO user) {...}
...
}

Necessity of the Base Class

Methods for Splitting a Base Class

/** Udser Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** SMS service */
@Autowired
private SmsService smsService;
/** System name */
@Value("${example.systemName}")
private String systemName;
...
}
/** example constant class */
public class ExampleConstants {
/** super user ID */
public static final long SUPPER_USER_ID = 0L;
...
}
/** User service class */
@Service
public class UserService {
/** Ger user function */
public UserDO getUser(Long userId) {...}
...
}
/** Company service class */
@Service
public class CompanyService {
/** User service */
@Autowired
private UserService userService;

/** Get the administrator */
public UserDO getManager(Long companyId) {
CompanyDO company = ...;
return userService.getUser(company.getManagerId());
}
...
}
/** User Aid Class */
public class UserHelper {
/** Get the user name */
public static String getUserName(UserDO user) {...}
...
}

The Business Code Is Written in the Controller Class

Phenomena Description

/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Get user function */
@ResponseBody
@RequestMapping(path = "/getUser", method = RequestMethod.GET)
public Result<UserVO> getUser(@RequestParam(name = "userId", required = true) Long userId) {
// Get user information
UserDO userDO = userDAO.getUser(userId);
if (Objects.isNull(userDO)) {
return null;
}

// Copy and return the user
UserVO userVO = new UserVO();
BeanUtils.copyProperties(userDO, userVO);
return Result.success(userVO);
}
...
}

A Special Case

/** Test Controller Class */
@Controller
@RequestMapping("/test")
public class TestController {
/** System name */
@Value("${example.systemName}")
private String systemName;

/** Access function */
@RequestMapping(path = "/access", method = RequestMethod.GET)
public String access() {
return String.format("You're accessing System (%s)!", systemName);
}
}
curl http://localhost:8080/test/access

Three-tier Server Architecture

The Persistence Layer Code Is Written in the Service Class

Main Problems

The Database Code Is Written in the Service

/** User Service Class */
@Service
public class UserService {
/** Session factory */
@Autowired
private SessionFactory sessionFactory;
/** Get user function based on job number */
public UserVO getUserByEmpId(String empId) {
// Assemble HQL statement
String hql = "from t_user where emp_id = '" + empId + "'";

// Perform database query
Query query = sessionFactory.getCurrentSession().createQuery(hql);
List<UserDO> userList = query.list();
if (CollectionUtils.isEmpty(userList)) {
return null;
}

// Convert and return user
UserVO userVO = new UserVO();
BeanUtils.copyProperties(userList.get(0), userVO);
return userVO;
}
}
/** User DAO CLass */
@Repository
public class UserDAO {
/** Session factory */
@Autowired
private SessionFactory sessionFactory;

/** Get user function based on job number */
public UserDO getUserByEmpId(String empId) {
// Assemble HQLstatement
String hql = "from t_user where emp_id = '" + empId + "'";

// Perform database query
Query query = sessionFactory.getCurrentSession().createQuery(hql);
List<UserDO> userList = query.list();
if (CollectionUtils.isEmpty(userList)) {
return null;
}

// Return user information
return userList.get(0);
}
}
/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Get user function based on job number */
public UserVO getUserByEmpId(String empId) {
// Query user based on job number
UserDO userDO = userDAO.getUserByEmpId(empId);
if (Objects.isNull(userDO)) {
return null;
}

// Convert and return user
UserVO userVO = new UserVO();
BeanUtils.copyProperties(userDO, userVO);
return userVO;
}
}
/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Get user function */
public UserVO getUser(String companyId, String empId) {
// Query database
UserParam userParam = new UserParam();
userParam.createCriteria().andCompanyIdEqualTo(companyId)
.andEmpIdEqualTo(empId)
.andStatusEqualTo(UserStatus.ENABLE.getValue());
List<UserDO> userList = userDAO.selectByParam(userParam);
if (CollectionUtils.isEmpty(userList)) {
return null;
}

// Convert and return users
UserVO userVO = new UserVO();
BeanUtils.copyProperties(userList.get(0), userVO);
return userVO;
}
}

The Redis Code Is Written in the Service Class

/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Redistemplate */
@Autowired
private RedisTemplate<String, String> redisTemplate;
/** User primary key mode */
private static final String USER_KEY_PATTERN = "hash::user::%s";
/** Save user function */
public void saveUser(UserVO user) {
// Convert user information
UserDO userDO = transUser(user);
// Save Redis user
String userKey = MessageFormat.format(USER_KEY_PATTERN, userDO.getId());
Map<String, String> fieldMap = new HashMap<>(8);
fieldMap.put(UserDO.CONST_NAME, user.getName());
fieldMap.put(UserDO.CONST_SEX, String.valueOf(user.getSex()));
fieldMap.put(UserDO.CONST_AGE, String.valueOf(user.getAge()));
redisTemplate.opsForHash().putAll(userKey, fieldMap);
// Save database user
userDAO.save(userDO);
}
}
/** User Redis Class */
@Repository
public class UserRedis {
/** Redistemplate */
@Autowired
private RedisTemplate<String, String> redisTemplate;
/** Primary key mode */
private static final String KEY_PATTERN = "hash::user::%s";

/** Save user function */
public UserDO save(UserDO user) {
String key = MessageFormat.format(KEY_PATTERN, userDO.getId());
Map<String, String> fieldMap = new HashMap<>(8);
fieldMap.put(UserDO.CONST_NAME, user.getName());
fieldMap.put(UserDO.CONST_SEX, String.valueOf(user.getSex()));
fieldMap.put(UserDO.CONST_AGE, String.valueOf(user.getAge()));
redisTemplate.opsForHash().putAll(key, fieldMap);
}
}
/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** User Redis */
@Autowired
private UserRedis userRedis;
/** Save user function */
public void saveUser(UserVO user) {
// 转化用户信息
UserDO userDO = transUser(user);
// Save Redis user
userRedis.save(userDO);
// Save database user
userDAO.save(userDO);
}
}

The Database Model Class Is Exposed to Interfaces

Symptom Description

/** User DAO Class */
@Repository
public class UserDAO {
/** Get user function */
public UserDO getUser(Long userId) {...}
}
/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Get user function */
public UserDO getUser(Long userId) {
return userDAO.getUser(userId);
}
}
/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
/** User service */
@Autowired
private UserService userService;
/** Get user function */
@RequestMapping(path = "/getUser", method = RequestMethod.GET)
public Result<UserDO> getUser(@RequestParam(name = "userId", required = true) Long userId) {
UserDO user = userService.getUser(userId);
return Result.success(user);
}
}

Existing Problems and Solutions

Three Methods for Project Building

A Less Recommended Suggestion

/** User DAO Class */
@Repository
public class UserDAO {
/** Calculate user function */
public Long countByParameter(QueryUserParameterVO parameter) {...}
/** Query user function */
public List<UserVO> queryByParameter(QueryUserParameterVO parameter) {...}
}
/** User Service Class */
@Service
public class UserService {
/** User DAO */
@Autowired
private UserDAO userDAO;
/** Query user function */
public PageData<UserVO> queryUser(QueryUserParameterVO parameter) {
Long totalCount = userDAO.countByParameter(parameter);
List<UserVO> userList = null;
if (Objects.nonNull(totalCount) && totalCount.compareTo(0L) > 0) {
userList = userDAO.queryByParameter(parameter);
}
return new PageData<>(totalCount, userList);
}
}
/** User Controller Class */
@Controller
@RequestMapping("/user")
public class UserController {
/** User service */
@Autowired
private UserService userService;
/** Query user function (with the page index parameters of startIndex and pageSize) */
@RequestMapping(path = "/queryUser", method = RequestMethod.POST)
public Result<PageData<UserVO>> queryUser(@Valid @RequestBody QueryUserParameterVO parameter) {
PageData<UserVO> pageData = userService.queryUser(parameter);
return Result.success(pageData);
}
}

Conclusion

Original Source

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store