rest api 응답과 테스트
오늘 한 것
- RestController 리턴형태 ResposneEntity 사용하기
- FileUtils의 업로드 경로 자원화 및 객체 업로드
- 상세 조회 페이지작성
- 메소드 명 변경
ex. select -> find / create -> save ..등
ResposneEntity 의 응답과 ajax 반응형태는 대략 이렇게
- 메소드 명 변경
@ResponseBody
@PostMapping("/api/v1/company")
public ResponseEntity<?> save(@RequestBody CompanySaveRequestDto request) throws Exception {
ResponseEntity<?> result;
try {
companyService.save(request);
result = new ResponseEntity<>(HttpStatus.OK) ;
}
catch(Exception e) {
e.printStackTrace();
result = new ResponseEntity<String>(e.getMessage(), HttpStatus.CONFLICT) ;
}
return result;
}
ResponseEntity 인스턴스 생성당시 제네릭을 사용하여 전송
$.ajax({
url : "/api/v1/company",
data: JSON.stringify(jsonForm),
type : 'POST',
contentType: 'application/json',
success : function() {
alert('저장하였습니다.');
},
error : function(request, status, error) {
alert("something goes wrong");
console.log("code:" + request.status + "\n" + "message:"
+ request.responseText + "\n" + "error:" + error);
}
});
별다른 것 없이 http.OK 하면 200 떨어지면서 success 로 받아들임
dataType : json 하면 응답형태 json 으로 받아서 사용못하더라능
FileUtils 경로 자원화
@Component("fileUtils")
public class FileUtils {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
private static S3Uploader s3Uploader;
private static String realPath;
private static String companyUploadDir;
@Autowired
FileUtils(S3Uploader s3Uploader , ServletContext context){
this.s3Uploader = s3Uploader;
this.realPath = context.getRealPath("/");
}
public static String getRealPath() {
return realPath;
}
@Value("${companyUploadDir}")
private void setCompanyUploadDir(String companyUploadDir) {
FileUtils.companyUploadDir = companyUploadDir;
}
public static String getCompanyFilePath() {
return companyUploadDir;
}
}
properties 에 존재하는 경로를 static으로 가져오기 위해 setCompanyUploadDir 정의
주의할 것은 클래스명.필드 를 명시해야 주입이된다.
this.field = param 이거 안됨
위를 사용해서 변환시에 파일 업로드 하는 걸로 바꿈
public Company toModel() throws Exception{
return Company.builder()
.comName(comName)
.comOwnerName(comOwnerName)
.comBuildDate(comBuildDate)
.comAddr(comAddr)
.comAddrCity(comAddrCity)
.comAddrState(comAddrState)
.comBizNum(comBizNum)
.files(FileUtils.uploadBase64Image(files,FileUtils.getCompanyFilePath()))
.city(City.builder().city(city).build())
.build();
}
@Transactional(rollbackFor = Exception.class)
public void save(CompanySaveRequestDto request) throws Exception{
Company company = request.toModel();
companyMapper.saveCompany(company);
companyMapper.saveCompanyCity(company);
companyMapper.saveCompanyFee(company);
companyMapper.saveCompanyDoc(company);
}
files 필드 부분에서 직접적으로 업로드를 시도한다.
io부분에 익셉션 처리가 되어있어서 throws를 추가.
해서 아래 save메소드가 좀더 정갈하게 바뀜
상세 조회 페이지 작성
restcontroller로 작성하려다가 web인 것을 인지하고 다시 indexcontroller로 돌아감
@GetMapping("company/{idx}")
public ModelAndView findCompany(@PathVariable Long idx) {
ModelAndView mav = new ModelAndView("company/detailView.tiles");
try {
mav.addObject("result",companyService.findByIdx(idx));
} catch (Exception e) {
this.logger.error("ERROR - ", e);
}
return mav;
}
간단한 get형태의 uri . rest api 패턴과 같게한다.
업로드한 파일목록을 가져오기위한 file ResultMap정의
<resultMap type="com.guivingAdmin.domain.vo.DocFile" id="docFile">
<id property="fileCode" column="FILE_CODE"/>
<result property="url" column="FILE_URL"/>
</resultMap>
DB 파일을 추가/수정할 때 신규 row를 insert하고 각 항목의 최상위건을 가져오도록 했었다.
그랬더니 필요한 파일 목록을 UI에 그릴수 없어 쿼리문에서 필요 항목까지 한 번에 조회해오는 것으로 했다.
이미 선언해놓은 FileCode를 UI단에 넘겨 그려놓고
요청한 데이터의 filecode와 비교하며 그려볼까도 했지만 그러면 중첩 foreach가 생기게되는 것..
docFile필드를 Map형태로 가져와서 Filecode를 key로 사용해 꺼내오는 방식을 사용해볼까
아무튼 위 때문에 쿼리문이 상당히 지저분해짐
<select id="findByIdx" resultMap="ResultMap.companyExt">
SELECT CY.COM_IDX, CY.COM_NAME, CY.COM_OWNER_NAME,
CY.COM_BUILD_DATE, CY.COM_BIZ_NUM, CY.COM_ADDR,
CY.COM_BIZ_TYPE_CODE, CY.COM_BIZ_TYPE_NAME,
CY.COM_BIZ_LICENSE_URL, CY.COM_AUTH_CODE, CY.COM_ADDR_CITY,
CY.COM_ADDR_STATE, CY.COM_ADDR_POSTAL_CODE,
CY.COM_GARAGE_IMG_URL, CY.COM_CLEAN_IMG_URL, CY.COM_FIX_IMG_URL, CY.COM_ETC_IMG_URL,
CD.FILE_CODE, CD.FILE_URL
FROM
TB_COMPANY CY
LEFT JOIN
(SELECT IFNULL(CD.COM_IDX,#{Idx}) AS COM_IDX,CF.FILE_CODE,CD.FILE_URL
FROM
(SELECT DOC_IDX, COM_IDX, FILE_CODE, FILE_URL, ISUSED
FROM TB_COM_DOC CD,
(SELECT MAX(CD.DOC_IDX) AS MAX_IDX
FROM TB_COM_DOC CD
GROUP BY CD.DOC_IDX) SUB
WHERE CD.DOC_IDX = SUB.MAX_IDX)CD
RIGHT JOIN VW_COMPNAY_FILE CF ON CD.FILE_CODE = CF.FILE_CODE AND CD.COM_IDX = #{Idx})CD
ON CD.COM_IDX = CY.COM_IDX
WHERE CY.COM_IDX = #{Idx}
</select>
Idx를 세군데나 쑤셔박았다. 내가 제일 싫어하는 스타일의 쿼리 ㅠㅠ
UI에서 간편하게 매핑할 수 있는 걸 해봐야겠다.
도메인 모델측에서
filecode를 사용하여 docfile list를 만들고 매칭되는 데이터만 넘겨줘도 될 듯
(애초에 이렇게 할 걸 쯧)
마지막으로 처음 사용해본 컨트롤러 테스트
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class IndexControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void findCompanyTest() throws Exception {
this.mockMvc.perform(get("/company/{idx}", 64))
.andExpect(status().isOk())
//.andExpect(jsonPath("$['result']", containsString("comName")))
.andDo(print());
}
}
아직 사용법을 잘몰라서 그런건지 view페이지에서 어떤 값이 매핑이 안되어서 나는 오류를 볼 수 가 없었다.
이부분 알아내면 훨씬 편하지 싶은데..
내일은 수정 기능까지
되도록 일관된 dto를 사용하는것이 제일 좋으니 그쪽으로 유도해보는걸로