Spring at Rowem
Backend development while at Rowem Inc.
backend Development
-
Java
-
API development for SBS inkigayo voting platform
- SDKs used : AWS SNS, AWS S3
- APIs used : Payletter, Apple login
-
Scheduling (Spring Framework) for Batch Job
- Code Optimization (e.g. for-loop)
- Refactoring for readability and reusability of codes
- Junit unit test
-
Git
- Pull Request, Code Review, Merge
- Branch : 'main < test < develop'
Code Optimization
/**
* Limit fetch size (query limit count) for each sql query execution
* so that it does not put stress on database
*/
final int fetchSize = AppConstants.DEFAULT_FETCH_SIZE;
// Total list count
final int listCount = batchApiMapper.getVoteListCnt();
// Limit for iteration
final int limit = listCount + fetchSize;
BatchVO param = new BatchVO();
for (int ii = 0; ii < limit;) {
param.setPage_index(ii);
param.setRecord_count_per_page(fetchSize);
List<BatchVoteVO> mainList = batchApiMapper.getVoteInfoList(param);
for (BatchPlayvoteVO m : mainList) {
batchApiMapper.updateVote(m);
}
ii += fetchSize;
}
// ...
Refactoring
/**
* API for executing voting process includes updating and retrieving from database
* refactoring helped to improve readability
*/
@Override
@Transactional
public ResultVO insertVote(VoteInsertVO param) throws Exception {
// Get vote info including target candidate that a user is requesting
VoteInsertVO vote = getVoteUserInfo(param);
// Calculate total vote points
// internal point system include point conversion!
setTotalVotePointInfo(vote);
// Operation for SELECT FOR UPDATE
// retrieves data for update (update is locked during Lock Wait Time)
VoteDetailUserVO detailUser = selectVoteDetailUserForUpdate(vote);
// Validate remaining user points
validateVoteInfo(vote, vote.getVote_use_count());
// Insert vote result data : tran_no, hist_seq
insertVoteHistory(vote);
// Process point deduction based on the user request which includes use point type
String voteUsePointType = param.getVote_use_point_type();
if (VoteUsePointType.SILVER.equals(voteUsePointType)) {
useSilverPoint(vote);
useGoldPoint(vote);
}
else if (VoteUsePointType.GOLD.equals(voteUsePointType)) {
useGoldPoint(vote);
}
// Insert another vote history data
// which is used for statistical purpose
// e.g. for future vote candidate recommendation or viewing voting history
insertVoteHist(vote);
// Update Vote aggregate data
detailUser.setVote_use_point(vote.getVote_use_point());
detailUser.setVote_count(vote.getVote_use_count());
updateVoteDetailUser(detailUser);
// Return remaining vote count for a user after the transaction is complete
// in case of a vote platform that restrict the vote counts for each user
if (!VoteLimitCountType.NOLIMIT.equals(vote.getVote_limit_cnt_type())) {
int remain_cnt = selectRemainCnt(vote);
ResultDoPlayVoteVO result = new ResultDoPlayVoteVO();
result.setVote_remain_cnt(remain_cnt);
result.setCode(ErrorCode.SUCCESS.getCode());
result.setMessage(getMessage(ErrorCode.SUCCESS.getKey()));
return result;
} else {
ResultVO result = new ResultVO();
result.setCode(ErrorCode.SUCCESS.getCode());
result.setMessage(getMessage(ErrorCode.SUCCESS.getKey()));
return result;
}
}
Unit test
package com.oo.ooo.home;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.rowem.passicon.SpringTestBase;
/**
* OO GET Test
*
* @author junho
*
*/
public class DataApiTest extends SpringTestBase {
@Autowired
private HomeApiService homeApiService;
@Autowired
private HomeApiMapper homeApiMapper;
@Autowired
private DataService dataService;
/**
* Delete data
*
* @throws Exception
*/
private void deleteData() throws Exception {
DataVO data = null;
do {
MyObj param = new MyObj();
param.setLogin_id("ooo")
// Find data to be deleted
data = dataApiMapper.selectMyData(param);
if (data != null) {
ResultVO result = dataService.deleteData(data);
assertEquals(ErrorCode.SUCCESS.getCode(), result.getCode());
}
} while(star_info != null);
}
/**
* Insert data
*
* @throws Exception
*/
private void insertData() throws Exception {
MyObj s = new MyObj();
s.setLogin_id("ooo")
ResultVO res = dataService.insertMyData(s);
assertEquals(ErrorCode.SUCCESS.getCode(), res.getCode());
}
/**
* 0-1 Home API test
*
* CASE1. mystar X, vote hist X, backoffice > recommend star list 0 (all deactivated: stat=2)
*
* @throws Exception
*/
@Test
public void testGetStarInfo_1() throws Exception {
String login_id = "ooo";
DataParamVO param = new DataParamVO();
param.setLogin_id(login_id);
// mystar X
deleteData();
// vote hist X
List<StarInfoVO> recom_votehist_list = homeApiMapper.selectStarVoteLogList(param);
assertEquals(0, recom_votehist_list.size());
DataResultVO result = (DataResultVO) homeApiService.getStarInfo(param);
assertEquals(null, result.getStar_info());
assertEquals(0, result.getRecom_votehist_list().size());
assertEquals(null, result.getRefresh_size());
assertEquals(0, result.getRecom_admin_list().size());
assertEquals(null, result.getVote_playvote_list());
assertEquals(null, result.getVote_indiv_rank());
assertEquals(null, result.getVote_battle_rank());
}
/**
* case2. mystar X, vote history X, backoffice > recommend star list at least 1 (activated stat=1)
*
* @throws Exception
*/
@Test
public void testGetStarInfo_2() throws Exception {
String login_id = "ooo";
DataParamVO param = new DataParamVO();
param.setLogin_id(login_id);
// mystar X
deleteData();
// vote history X
List<StarInfoVO> recom_votehist_list = homeApiMapper.selectStarVoteLogList(param);
assertEquals(0, recom_votehist_list.size());
DataResultVO result = (DataResultVO) homeApiService.getStarInfo(param);
assertEquals(null, result.getStar_info());
assertEquals(0, result.getRecom_votehist_list().size());
assertEquals(null, result.getRefresh_size());
assertEquals(Boolean.TRUE, result.getRecom_admin_list().size() > 0);
assertEquals(null, result.getVote_playvote_list());
assertEquals(null, result.getVote_indiv_rank());
assertEquals(null, result.getVote_battle_rank());
}
}
package com.oo.ooo;
import javax.servlet.ServletContext;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* SpringTestBase class
*
* @author junho
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml",
"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/test/resources/spring/context-test-mapper.xml", })
@WebAppConfiguration
@ActiveProfiles("local")
public class SpringTestBase {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
protected ObjectMapper objectMapper;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setDefaultPrettyPrinter(new DefaultPrettyPrinter());
}
/**
* print object as JSON
*
* @param name
* @param value
*/
protected void printJson(String name, Object value) {
try {
logger.info("{}:\n{}", name, objectMapper.writeValueAsString(value));
} catch (JsonProcessingException e) {
logger.error("error :", e);
}
}
@Test
public void isWebAppContextLoadingProperly() {
ServletContext servletContext = wac.getServletContext();
Assert.assertNotNull(servletContext);
Assert.assertTrue(servletContext instanceof MockServletContext);
}
}