예전에 eclipse 교육 받을 때 백쪽에 항상 Vo, Dao, DaoImpl, Service(★), ServiceImpl, Controller(★★) 이렇게 최소 6종세트가 필요했다.
(★, ★★: 이하부터는 Svc, Ctrl로 표시할 예정)
sts4로 넘어오면서 DaoImpl가 생략되었다.
chat gpt에게 물어보니 Dao까지도 생략 가능하더라~ 즉: Vo, Svc, SvcImpl, Ctrl 4종세트로 줄여짐!
그래서 개인 플젝에 바로 적용해봤다.
진행하려는 건 sts4에서 war/thymeleaf/lombok/mariaDB/mybatis, 첨부파일 포함된 쇼핑몰이다.
1, Vo
private String pimgStr; // 첨부파일명. db에는 varchar로 저장
private MultipartFile pimg; // 첨부파일 자체. db엔 없고 백-프론트에만 사용
2, Svc
ㄴ Dao 대신 mapper 역할 맡기기
@Mapper
public interface PrdSvc {
List<PrdVo> prdList(PrdVo vo); // 상품 리스트 관리
void addPrd(PrdVo vo); //상품 추가
}
3, SvcImpl
ㄴ Svc에서 매핑하기
@Service
public class PrdSvcImpl {
@Autowired
PrdSvc prdMapper; //mapper
public List<PrdVo> prdList(PrdVo vo) {
return prdMapper.prdList(vo);
}
public void addPrd(PrdVo vo) {
prdMapper.addPrd(vo);
}
}
4.1, application.properties
ㄴ 저장경로 선언을 위해 아래 문구 추가:
file.upload-dir=src/main/resources/static/img
4.2, FileStorageService
ㄴ 파일 저장경로 처리를 위한 별도의 class
선언한 저장경로 ${file.upload-dir} 을 @Value에 대입
@Service
public class FileStorageService {
@Value("${file.upload-dir}")
private String uploadDir;
@PostConstruct
public void init() {
File uploads = new File(uploadDir);
//프론트에선 파일 첨부를 필수로 지정했어도, 백에서도 첨부파일 없는 경우 대비
if (!uploads.exists()) {
uploads.mkdirs();
}
}
public String getUploadDir() {
return uploadDir;
}
}
4.3, Ctrl
ㄴ SvcImpl에서 매핑하기
@RequestMapping("/prd/")
@Controller
public class PrdCtrl {
PrdCtrl(){
System.out.println("PrdCtrl 생성자");
}
@Autowired
PrdSvcImpl prdSvcImpl; //mapper
@GetMapping("prdList") // 상품 리스트 조회
public String prdList(Model model) {
System.out.println("prdList");
PrdVo vo=new PrdVo(); // 필요한 경우 값 설정
List<PrdVo> li=prdSvcImpl.prdList(vo);
model.addAttribute("li", li);
model.addAttribute("lisize", li.size());
return "prd/prdList";
}
@GetMapping("addPrdForm") //상품 추가 시작
public String addPrdForm() {
System.out.println("addPrdForm");
return "prd/addPrdForm";
}
@PostMapping("addPrd") //상품정보 (첨부 포함) 제출
public String addPrd(MultipartHttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("addPrd");
PrdVo vo = new PrdVo();
// 첨부파일 처리
Part filePart = request.getPart("pimg");
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
//application, FileStorageService에서 정의한 경로(resources/static/img)로 저장하도록 설정
String realFolder = fileStorageService.getUploadDir();
//파일 경로 생성
File file = new File(realFolder, fileName);
filePart.write(file.getAbsolutePath());
// 콘솔에 저장된 파일 경로 출력
System.out.println("저장 경로: " + file.getAbsolutePath());
// 기타 값 처리
vo.setPimgStr(fileName);
vo.setPname(request.getParameter("pname"));
vo.setPdesc(request.getParameter("pdesc"));
vo.setPprice(Integer.parseInt(request.getParameter("pprice")));
vo.setPstock(Integer.parseInt(request.getParameter("pstock")));
vo.setPdelifee(Integer.parseInt(request.getParameter("pdelifee")));
// db에 추가
prdSvcImpl.addPrd(vo);
return "redirect:prdList";
}
}
mapper.xml
<mapper namespace="com.mall.prd.PrdSvc"> <!-- Dao 대신 Svc 씀 -->
<select id="prdList" resultType="com.mall.prd.PrdVo">
SELECT * FROM products order by product_code desc
</select>
<insert id="addPrd" parameterType="com.mall.prd.PrdVo">
INSERT INTO products (
pimgStr,
...
) VALUES (
#{pimgStr},
...
)
</insert>
</mapper>
상품 추가 양식
<form action="/prd/addPrd"
method="post" enctype="multipart/form-data">
<table class="addPrdTable">
<tr>
<th>pname</th>
<td><input type="text" name="pname"></td>
</tr>
<tr>
<th>pimg</th>
<td><input type="file" name="pimg" required="required"></td>
</tr>
...
</table>
<br>
<input type=submit value=등록 class=button>
 
<input type="reset" value="다시 입력" class=button>
</form>
상품 리스트
<h3 th:text="'상품건수: ' + ${lisize} + '건'"></h3>
<table>
<tr class="tr_color">
<th>no</th>
<th>product_code</th>
<th>pimg</th>
...
</tr>
<tr th:each="m, stat : ${li}" class="tr_color">
<td th:text="${stat.count}"></td> <!-- db와 관계없는 자동증가하는 순번 -->
<td th:text="${m.product_code}"/>
<td>
<img th:src="@{/img/}+${m.pimgStr}" width="100" />
</td>
...
</tr>
</table>
유의할 점은 파일 저장경로 설정 시,
db 통해 직접 레코드 추가했을 때에 저장된 경로와 동일하게
'resources/static/img'에 저장되도록 하는 것이다.
해당 img 폴더는 플젝 생성할 때부터 미리 추가해두는 게 좋겠지.
그렇지 않으면, db가 아닌 프론트에서 이미지 올렸을 때,
하단 webapp 폴더에 'static/img' 폴더가 자동으로 생성되고, 이미지는 이쪽에 저정된다!
큰 문제는 아니라지만 개발ㆍ배포 간에 통일성이 떨어지고,
직접 겪은 바로는 이미지가 출력 안 되는 현상이 있었다.
처음엔 당황했지만 저장경로 재설정하니까 이미지가 제대로 출력됐다.
ps: 명탐정 코난 주30년 축하한당.