//컨트롤러 빈에 이름지정
@Controller("adminGoodsController")
@RequestMapping(value="/admin/goods")
public class AdminGoodsControllerImpl extends BaseController implements AdminGoodsController{
private static final String CURR_IMAGE_REPO_PATH = "C:\\shopping\\file_repo";
@Autowired
private AdminGoodsService adminGoodsService;
@RequestMapping(value="/adminGoodsMain.do" ,method={RequestMethod.POST,RequestMethod.GET})
//@RequestParam 어노테이션은 HTTP 요청 파라미터를 컨트롤러 메소드의 매개변수에 매핑하는 데 사용
public ModelAndView adminGoodsMain(@RequestParam Map<String, String> dateMap,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String viewName=(String)request.getAttribute("viewName");
ModelAndView mav = new ModelAndView(viewName);
HttpSession session=request.getSession();
session=request.getSession();
session.setAttribute("side_menu", "admin_mode"); //마이페이지 사이드 메뉴로 설정한다.
// Map의 get메서드를 이용해서 key값을 이용해 value값을 자바 변수에 넣어준다.
String fixedSearchPeriod = dateMap.get("fixedSearchPeriod");
String section = dateMap.get("section");
String pageNum = dateMap.get("pageNum");
String beginDate=null,endDate=null;
//basecontroller에 있는 calcSearchPeriod에 넣어줘 날짜를 String으로 나눈다. basecontroller는 추후에 블로그에서 다룬다.
String [] tempDate=calcSearchPeriod(fixedSearchPeriod).split(",");
beginDate=tempDate[0];
endDate=tempDate[1];
dateMap.put("beginDate", beginDate);
dateMap.put("endDate", endDate);
// pageNum , section 링크에서 자세한 내용 참고
Map<String,Object> condMap=new HashMap<String,Object>();
if(section== null) {
section = "1";
}
condMap.put("section",section);
if(pageNum== null) {
pageNum = "1";
}
condMap.put("pageNum",pageNum);
condMap.put("beginDate",beginDate);
condMap.put("endDate", endDate);
// GoodsVO 리스트를 만들어서 comdMap을 넣어 query문 갔다오게 하고 mav객체에
//넣어준후 반환, 추가로 위에서 만든 변수들 모두 mav객체에 넣어준 후 반환 ->
// jsp에서 확인가능
List<GoodsVO> newGoodsList=adminGoodsService.listNewGoods(condMap);
mav.addObject("newGoodsList", newGoodsList);
String beginDate1[]=beginDate.split("-");
String endDate2[]=endDate.split("-");
mav.addObject("beginYear",beginDate1[0]);
mav.addObject("beginMonth",beginDate1[1]);
mav.addObject("beginDay",beginDate1[2]);
mav.addObject("endYear",endDate2[0]);
mav.addObject("endMonth",endDate2[1]);
mav.addObject("endDay",endDate2[2]);
mav.addObject("section", section);
mav.addObject("pageNum", pageNum);
return mav;
}
https://velog.io/@lee41180612/AttiWell-pageNumsection-%EA%B5%AC%ED%98%84
adminGoodsMain
○ 요청 파라미터로 jsp에서 넘어온 날짜를 Map으로 받아옴
○날짜처리 -> calcSearchPeriod(fixedSearchPeriod)를 통해 처리하고 메서드 지역번수에 날짜 저장
○pageNum section 초기화
○condMap에 위에서 날짜 처리한 begindate, enddate 및 section, pageNum 넣는다.
○goodsVO에 condMap을 넣어 조건에 맞는 GoodsVO리스트를 가져온다.
○조회된 상품 리스트를 mav에 추가 -> jsp로 데이터 전송
결국 -> jsp의 조회날짜범위, 페이지 섹션을 가져와서 상품리스트를 조회해서 jsp로 다시 리턴한다.
//@RequestParam 어노테이션은 HTTP 요청 파라미터를 컨트롤러 메소드의 매개변수에 매핑하는 데 사용
@RequestMapping(value="/adminGoodsMain.do" ,method={RequestMethod.POST,RequestMethod.GET})
public ModelAndView adminGoodsMain(@RequestParam Map<String, String> dateMap,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String viewName=(String)request.getAttribute("viewName");
ModelAndView mav = new ModelAndView(viewName);
HttpSession session=request.getSession();
session=request.getSession();
session.setAttribute("side_menu", "admin_mode"); //마이페이지 사이드 메뉴로 설정한다.
// admingoods.jsp 에서 날짜 데이터 javascript로 url로 controller에 전달
String fixedSearchPeriod = dateMap.get("fixedSearchPeriod");
String section = dateMap.get("section");
String pageNum = dateMap.get("pageNum");
String beginDate=null,endDate=null;
//basecontroller에 있는 calcSearchPeriod에 넣어줘 날짜를 String으로 나눈다. basecontroller는 추후에 블로그에서 다룬다.
String [] tempDate=calcSearchPeriod(fixedSearchPeriod).split(",");
beginDate=tempDate[0];
endDate=tempDate[1];
dateMap.put("beginDate", beginDate);
dateMap.put("endDate", endDate);
Map<String,Object> condMap=new HashMap<String,Object>();
if(section== null) {
section = "1";
}
condMap.put("section",section);
if(pageNum== null) {
pageNum = "1";
}
condMap.put("pageNum",pageNum);
condMap.put("beginDate",beginDate);
condMap.put("endDate", endDate);
// GoodsVO 리스트를 만들어서 comdMap을 넣어 query문 갔다오게 하고 mav객체에
//넣어준후 반환, 추가로 위에서 만든 변수들 모두 mav객체에 넣어준 후 반환 ->
// jsp에서 확인가능
List<GoodsVO> newGoodsList=adminGoodsService.listNewGoods(condMap);
mav.addObject("newGoodsList", newGoodsList);
String beginDate1[]=beginDate.split("-");
String endDate2[]=endDate.split("-");
// model 객체에 데이터 담아서 view로 쏴준다.
mav.addObject("beginYear",beginDate1[0]);
mav.addObject("beginMonth",beginDate1[1]);
mav.addObject("beginDay",beginDate1[2]);
mav.addObject("endYear",endDate2[0]);
mav.addObject("endMonth",endDate2[1]);
mav.addObject("endDay",endDate2[2]);
mav.addObject("section", section);
mav.addObject("pageNum", pageNum);
return mav;
}
adminGoodsService.listNewGoods(condMap);
비즈니스 로직 처리
dao에 있는 seletNewGoodsList를 conmap조건에 맞게 조회하겠다.
@Override
public List<GoodsVO> listNewGoods(Map condMap) throws Exception{
return adminGoodsDAO.selectNewGoodsList(condMap);
}
adminGoodsDAO.selectNewGoodsList(condMap);
1.반환 값 List 이기 때문에 (ArrayList)로 묶어줌
++) 중요!!! sqlSession의 메서드에 따라 반환값이 List인지 Map인지 달라짐
2. 자바 데이터를 자료구조에 담아서 sql문에 표현식으로 나타낼 수 있음
@Override
public List<GoodsVO>selectNewGoodsList(Map condMap) throws DataAccessException {
ArrayList<GoodsVO> goodsList=(ArrayList)sqlSession.selectList("mapper.admin.goods.selectNewGoodsList",condMap);
return goodsList;
}
mapper.admin.goods.selectNewGoodsList",condMap);
CDATA -> xml 형식을 배제하고 문자 그대로 인식 , 여기에서는 sql문 문자그대로 넣어주기 위함
#{} 을 통해
<select id="selectNewGoodsList" resultMap="goodsResult" parameterType="java.util.Map" >
<![CDATA[
select * from (
select rowNum as recNum,
goods_id,
goods_title,
goods_sales_price,
to_char(goods_creDate,'YYYY-MM-DD') as goods_creDate
from (
select goods_id,
goods_title,
goods_sales_price,
goods_creDate
from t_shopping_goods
where to_char(goods_creDate,'YYYY-MM-DD') between #{beginDate} and #{endDate}
order by goods_creDate desc
)
)
where
recNum between (#{section}-1)*100+ (#{pageNum}-1)*10+1 and (#{section}-1)*100+(#{pageNum})*10
]]>
</select>
컨트롤러
addNewGoods
이 메소드는 파일 업로드와 함께 multipart 요청을 처리
MultipartHttpServletRequest든 HttpServletRequest는 session든 간에 값에 둘의 세션 객체는 동일해서 member info를 불러올 수 있다.
정리)
1.폼에서 새로운 상품 정보를 받아와서 enu에 저장후 newGoodsMap에 저장
2.세션에서 멤버정보를 가져와서 memberid를 알아낸다.
3.이미지 파일의 등록자파일 vo 등록자id에 멤버id를 넣어주고 리스트로 만들어 newGoodsMap에 저장
4. 이미지 파일을 basecontroller의 upload메서드를 이용하여 temp폴더에 저장
5.http폼 응답헤더 설정
6. 실패 성공 예외처리하여 메세지 보냄, 성공하면 7번, 실패하면 실패메시지
7. File 클래스를 사용하여 temp에 있는 파일 실제 본 폴더로 이동
폼에서 얻은 새로운 상품 정보받아와서 newGoodsMap에 저장, 세션에서 멤버정보받아와서 memberID 이미지파일vo에 저장
이미지파일 vo를 리스트로 만들어서 newGoodsMap에 저장
이 newGoodsMap을 서비스 dao 를 통해 실제 DB에 저장
1.이 과정에서 시퀀스를 사용하여 자동으로 상품테이블에 key값을 생성하고 기본키 goods_id로 반환 및 newGoodsMap에있는 상품 관련 데이터를 DB에 넣어준다.
2. 위에 상품테이블에 데이터 넣을때 만든 goods_id를 image테이블에 넣어주고 image테이블 기본키는 마찬가지로 시퀀스 생성해서 넣어준다. 또한 3번에서 이미지파일 리스트를 이미지테이블에 넣어준다.
//MultipartHttpServletRequest: 파일 업로드를 처리하기 위해 사용되는 특수한 HttpServletRequest 이다.
@RequestMapping(value="/addNewGoods.do" ,method={RequestMethod.POST})
public ResponseEntity addNewGoods(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws Exception {
//요청과 응답의 인코딩을 UTF-8로 설정합니다. --> 다양한 문자를 올바르게 처리하여
// 문자깨짐 방지
multipartRequest.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
String imageFileName=null;
//정리) 폼에서 보낸 값들을 newGoodsMap에 저장
Map newGoodsMap = new HashMap();
//multipartRequest.getParameterNames 반환 형태 -> enumeration(열거)
Enumeration enu=multipartRequest.getParameterNames();
//enu에 요소가 더있는지 확인 있으면 map에 key,value값 넣어주기
//우선 그럼 여기서 addnewgood.jsp form에서 보낸 select, option , 이미지 key value값 다들어가 있다.
while(enu.hasMoreElements()){
String name=(String)enu.nextElement();
String value=multipartRequest.getParameter(name);
newGoodsMap.put(name,value);
}
//정리)세션에 담긴 멤버 정보에서 멤버 ID를 추출
//세션 생성해서 세션 객체에 담긴 memberinfo로 저장된 객체를 가져온다.
HttpSession session = multipartRequest.getSession();
MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
String reg_id = memberVO.getMember_id();
//정리) 이미지 파일 VO에 등록자 ID를 설정하고 이미지파일vo리스트에 추가 , 그 후 이미지파일 리스트 항목을 위에 선언한 newGoodsMap에 추가
// basecontroller의 upload 메서드 가져옴. basecontroller 의 upload메서드는 파일을 temp폴더에 저장한다!!!!
List<ImageFileVO> imageFileList =upload(multipartRequest);
if(imageFileList!= null && imageFileList.size()!=0) {
for(ImageFileVO imageFileVO : imageFileList) {
imageFileVO.setReg_id(reg_id);
}
newGoodsMap.put("imageFileList", imageFileList);
}
String message = null;
ResponseEntity resEntity = null;
//http요청 및 응답헤더 다룸, 클라이언트에게 응답할 때 내용이 html형식이며 utf-8 인코딩을 사용함
/*정리) http폼 응답헤더 설정, service로 위에 newgoodsmap보냄
*
* */
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "text/html; charset=utf-8");
try {
//위에서 form에서 담아뒀던 key value값들 전부 서비스 로 가게 해줌
int goods_id = adminGoodsService.addNewGoods(newGoodsMap);
if(imageFileList!=null && imageFileList.size()!=0) {
for(ImageFileVO imageFileVO:imageFileList) {
imageFileName = imageFileVO.getFileName();
//임시폴더를 거쳐서 가는 이유가 이미지 저장할때 본폴더에 저장할때 오류가 나면 본폴더 초기화해야할 수 도 있으니까
//그러면 원래 잘 저장되어있던 이미지도 다 날아가니까 우선 temp에 저장해놓고 문제 엎으면 목적지로 가게끔 한다.
//File 클래스는 경로설정 하는데 사용 -> 아까 basecontroller의 upload메서드에서 temp폴더에 저장한 파일을 목적지 폴더로 옮긴다.
File srcFile = new File(CURR_IMAGE_REPO_PATH+"\\"+"temp"+"\\"+imageFileName);
File destDir = new File(CURR_IMAGE_REPO_PATH+"\\"+goods_id);
//파일 이미지 경로를 temp에서 goods_id인 폴더로 옮김 (아래 메서드에 의해 temp에 남아있는 파일은 삭제 됨)
FileUtils.moveFileToDirectory(srcFile, destDir,true);
}
}
//성공적으로 완료했을시 성공 메시지 작성하고 원하는 jsp로 가게해줌
message= "<script>";
message += " alert('새상품을 추가했습니다.');";
message +=" location.href='"+multipartRequest.getContextPath()+"/admin/goods/addNewGoodsForm.do';";
message +=("</script>");
}catch(Exception e) {
// 예외가 발생했을 때 동일한 조건의 temp 폴더에 저장된 파일들을 삭제
//이를 통해 파일 업로드 과정에서 문제가 발생하면 temp 폴더에 남아 있는 임시 파일들을 정리
if(imageFileList!=null && imageFileList.size()!=0) {
for(ImageFileVO imageFileVO:imageFileList) {
imageFileName = imageFileVO.getFileName();
File srcFile = new File(CURR_IMAGE_REPO_PATH+"\\"+"temp"+"\\"+imageFileName);
srcFile.delete();
}
}
message= "<script>";
message += " alert('오류가 발생했습니다. 다시 시도해 주세요');";
message +=" location.href='"+multipartRequest.getContextPath()+"/admin/goods/addNewGoodsForm.do';";
message +=("</script>");
e.printStackTrace();
}
//ResponseEntity는 응답 본문, 응답 헤더, 상태 코드를 포함하는 객체로
//이를 통해 서버에서 클라이언트로 다양한 형태의 응답을 보낼 수 있다.
resEntity =new ResponseEntity(message, responseHeaders, HttpStatus.OK);
return resEntity;
}
service
addNewGoods
@Override
public int addNewGoods(Map newGoodsMap) throws Exception{
int goods_id = adminGoodsDAO.insertNewGoods(newGoodsMap);
ArrayList<ImageFileVO> imageFileList = (ArrayList)newGoodsMap.get("imageFileList");
for(ImageFileVO imageFileVO : imageFileList) {
imageFileVO.setGoods_id(goods_id);
}
adminGoodsDAO.insertGoodsImageFile(imageFileList);
return goods_id;
}
DAO
insertNewGoods
@Override
public int insertNewGoods(Map newGoodsMap) throws DataAccessException {
sqlSession.insert("mapper.admin.goods.insertNewGoods",newGoodsMap);
return Integer.parseInt((String)newGoodsMap.get("goods_id"));
}
xml
mapper.admin.goods.insertNewGoods
id="insertNewGoods"는 이 SQL 문의 식별자
parameterType="java.util.Map"은 이 SQL 문이 Java의 Map 객체를 파라미터로 받는다
selectKey 태그는 SQL 삽입 작업 전에 실행되는 SQL 문을 정의
이 SQL 문은 데이터베이스 시퀀스(seq_goods_id)에서 다음 값을 가져와 새로운 상품 ID로 사용합니다.
※시퀀스 : 고유한 값을 자동을 생성하기 위해서 사용, DB에 명시적으로 보이지는 않지만 저장되어있다.따라서 테이블도 dummy테이블 사용 , nextval은 다음값을 생성하고 반환하는 역할
seq_goods_id.nextval 이게 goods_id로 들어간다
<insert id="insertNewGoods" parameterType="java.util.Map">
<selectKey resultType="String" keyProperty="goods_id" order="BEFORE">
<!-- select seq_goods_id.nextval from dual -->
select seq_goods_id.nextval as goods_id from dual
</selectKey>
<![CDATA[
insert into t_shopping_goods(
goods_id,
goods_sort,
goods_title,
goods_price,
goods_sales_price,
goods_status,
goods_intro
) values (
#{goods_id},
#{goods_sort},
#{goods_title},
#{goods_price},
#{goods_sales_price},
#{goods_status},
#{goods_intro}
)
]]>
</insert>
insertGoodsImageFile
@Override
public void insertGoodsImageFile(List fileList) throws DataAccessException {
for(int i=0; i < fileList.size();i++){
ImageFileVO imageFileVO=(ImageFileVO)fileList.get(i);
sqlSession.insert("mapper.admin.goods.insertGoodsImageFile",imageFileVO);
}
}
이미지 파일 기본키 시퀀스로 자동화해서 저장
<insert id="insertGoodsImageFile" parameterType="imageFileVO" >
<selectKey resultType="int" keyProperty="image_id" order="BEFORE">
select seq_image_id.nextval from dual
</selectKey>
<![CDATA[
insert into t_goods_detail_image (image_id,
goods_id,
fileName,
fileType,
reg_id)
values(#{image_id},
#{goods_id},
#{fileName},
#{fileType},
#{reg_id} )
]]>
</insert>
adminGoodsMain.jsp 에서 상품이름을 누르면 그 상품의 goods_id와 함께 수정폼으로 들어가게 된다. 핵심은 goods_id 받아서 상품, 이미지 데이터 가져와서 폼에 나타낸다.
href="${pageContext.request.contextPath}/admin/goods/modifyGoodsForm.do?goods_id=${item.goods_id}">
위에서 url로 쏴준 goods_id를 requestparam으로 받고 서비스로 goods_id 전달
//수정 폼 보여줌 modifygoodsform.jsp의 controller 역할
@RequestMapping(value="/modifyGoodsForm.do" ,method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView modifyGoodsForm(@RequestParam("goods_id") int goods_id,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String viewName=(String)request.getAttribute("viewName");
ModelAndView mav = new ModelAndView(viewName);
Map goodsMap=adminGoodsService.goodsDetail(goods_id);
mav.addObject("goodsMap",goodsMap);
return mav;
}
@Override
public Map goodsDetail(int goods_id) throws Exception {
Map goodsMap = new HashMap();
GoodsVO goodsVO=adminGoodsDAO.selectGoodsDetail(goods_id);
List imageFileList =adminGoodsDAO.selectGoodsImageFileList(goods_id);
goodsMap.put("goods", goodsVO);
goodsMap.put("imageFileList", imageFileList);
return goodsMap;
}
목적 -> goods_id를 받아 상품데이터 vo에 넣는다.
쿼리에서 왜 main_image만 조건 걸어줬나? -> file type 이 main_image 만 판별해주면 jsp에서 c:choose로 다른 타입(detail_image)으로 판별가능하기때문
정리) 결국 main_image는 jsp에서 조건만 걸어주고 이미지를 직접적으로 나타내는건 이미지리스트 쓴다.@Override public GoodsVO selectGoodsDetail(int goods_id) throws DataAccessException{ GoodsVO goodsBean = new GoodsVO(); goodsBean=(GoodsVO)sqlSession.selectOne("mapper.admin.goods.selectGoodsDetail",goods_id); return goodsBean; }
<select id="selectGoodsDetail" resultMap="goodsResult" parameterType="String" > <![CDATA[ select g.*,to_char(g.goods_credate,'YYYY-MM-DD') as goods_credate, d.fileName from t_shopping_goods g, t_goods_detail_image d where g.goods_id=d.goods_id and d.filetype='main_image' and g.goods_id=#{goods_id} order by g.goods_id ]]> </select>
상품 아이디에 맞는 이미지 반환 -> 메인이미지, 상세이미지같이 이미지가 여러개일 수 있어서
List로 반환@Override public List selectGoodsImageFileList(int goods_id) throws DataAccessException { List imageList=new ArrayList(); imageList=(List)sqlSession.selectList("mapper.admin.goods.selectGoodsImageFileList",goods_id); return imageList; }
<select id="selectGoodsImageFileList" resultMap="imageResult" parameterType="String" > <![CDATA[ select * from t_goods_detail_image where goods_id=#{goods_id} order by image_id asc ]]> </select>