Jam's story

[Spring] Spring과 MyBatis 본문

Spring

[Spring] Spring과 MyBatis

애플쩀 2022. 7. 22. 11:13

MyBatis

ORM 프레임워크중에

  • 마이바티스
  • 하이버네이트
  • JPA 등등

p.565

  1. 스프링 4.x 에는 mybatis (ibatis 2.0) 연동기능포함 X
    • 스프링 3.x
  2. mybatis 를 스프링과 연동하는 과정 (방법)
    • mybatis-spring 모듈 추가 - pom.xml
      1. mybatis-spring - DB연결, 트랜잭션
      2. mybatis
    • SqlSessionFactoryBeaan 을 이용해서 SqlSessionFactory 설정 - rootContext.xml
      1. mybatis-spring 모듈의 핵심기능 클래스
        • SqlSessionFactoryBean
          • mapperLocations 속성
        • SqlSessionTemplate
    • 트랜잭션 설정
    • mybatis 를 통해서 DAO 구현
      1. ++++ SqlSession 이용해서 구현 ++++
      2. 매퍼동적생성 이용해서 구현

1️⃣ pom.xml

<!-- 11.  p563 mybatis-spring, mybatis 모듈 2개 추가 -->
      <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
      <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.2.3</version>
      </dependency>
      <!-- 12. -->
      <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
      <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis-spring</artifactId>
         <version>1.2.2</version>
      </dependency>

 

 

2️⃣[SqlSession]FactoryBean을 이용해서 SqlSessionFactory 설정

root.context.xml

<!-- mybatis-spring.jar 모듈의 핵심  빈 객체    -  Mapper XML 파일 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations">
           <list>
             <value>classpath:org/doit/web/newlecture/dao/mapper/NLNoticeDao.xml</value> 
           </list>
        </property>
    </bean>

  <!-- DAO 구현하는 빈 객체 등록    -->
    <bean id="sqlSession"  class="org.mybatis.spring.SqlSessionTemplate">
      <constructor-arg ref="sqlSessionFactory"></constructor-arg>
    </bean>

패키지와 파일 만들기

3️⃣NLNoticeDao.xml

형식

<mapper namespace="org.doit.web.newlecture.dao.인터페이스명">
    <select id="함수명">쿼리</select>
    <delete id="함수명">쿼리</delete>
${param1} 그대로

#{param1} 자료형에 맞게 변환

if -  mybatis 의 동적쿼리

${} 쿼리에 넣을 때 혹은 LIKE

#{} 문자열 넣을 때

이제 NLNoticeDao.java 파일이 필요가 없이 인터페이스만 있으면 된다.
resultType : 결과값의 type.
keyProperty : 다음 쿼리에 대입될 변수명.
order : 실행시점.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.doit.web.newlecture.dao.NoticeDao">

<!-- 샘플 
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
 -->  
 
 <!-- id 속성값은  메서드명 -->
 <!-- String field, String query -->
 <!-- ${ param1 }            ${ param2 } -->
 <!-- #{ param1 }           #{ param2 }   전달된 값을 자료형에 맞게 변환 -->
 <select id="getCount" resultType="Integer">
     SELECT COUNT(*) CNT  
	 FROM NOTICES  
	 WHERE ${ param1 } LIKE '%${ param2 }%'
 </select>
 
 <!-- 10:05 수업시작 -->
 <!-- (int page, String field, String query)  -->
      <!-- param1         param2        param3 --> 
<!-- List<Notice> -->
 <select id="getNotices"  resultType="org.doit.web.newlecture.vo.Notice">  
     SELECT * 
	    FROM  
		            ( 
		                   SELECT ROWNUM NUM, N.*  
		                    FROM (  
		                                    SELECT *  
		                                    FROM NOTICES  
		                                    WHERE ${ param2 } LIKE '%${ param3 }%' 
		                                ORDER BY REGDATE DESC 
		                            ) N 
		             ) 
		  WHERE NUM BETWEEN 1 + (#{ param1 }-1)*15 AND 15 + (#{ param1 }-1)*15
 </select>
 
 <!-- 매개변수의 이름을 그대로 사용가능 -->
 <!-- 
 <delete id="delete">
      DELETE FROM  NOTICES
	  WHERE SEQ= #{ seq } 
 </delete> 
 --> 
 
 <!-- update( Notice notice )  notice.getTitle() , -->
 <!-- 문제점  첨부된 파일이 없는 경우에는 , FILESRC= :filesrc  X -->
 <!-- mybatis의 동적 SQL -->
 <update id="update"  parameterType="org.doit.web.newlecture.vo.Notice">
    UPDATE NOTICES 
	 SET TITLE=#{ title }, CONTENT=#{content}
	 <if test="filesrc != null">
	  , FILESRC=#{ filesrc }
	 </if> 
	 WHERE SEQ=#{seq}
 </update>
 
 <!-- (String seq)  -->
 <select id="getNotice" resultType="org.doit.web.newlecture.vo.Notice">  
   <![CDATA[
     SELECT * 
	 FROM NOTICES 
	 WHERE SEQ = #{ seq }
	 ]]>
 </select>
 
 <!-- insert(Notice notice) -->
 <insert id="insert">
 
    <selectKey resultType="String"  order="BEFORE" keyProperty="seq">
        SELECT MAX(TO_NUMBER(SEQ))+1 
        FROM NOTICES
    </selectKey>
 
     INSERT INTO NOTICES 
	 ( SEQ, TITLE, CONTENT, WRITER, REGDATE, HIT, FILESRC) 
	 VALUES 			
	 (  #{ seq } , #{ title }, #{ content } , #{ writer  }, SYSDATE, 0, #{filesrc, javaType=String,  jdbcType=VARCHAR} )
 </insert>
 
 <update id="hitUp">
         update notices  
		 set hit = hit + 1  
		 where seq = #{ seq }
 </update>
 
 <select id="getHit" resultType="Integer">
	     select hit  
		  from notices 
	  	 where seq = #{ seq }
	</select>
 
</mapper>

 

 

4️⃣NoticeDao.java -인터페이스

package org.doit.web.newlecture.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.doit.web.newlecture.vo.Notice;
import org.springframework.transaction.annotation.Transactional;  

public interface NoticeDao { 
 
	public int getCount(String field, String query) throws ClassNotFoundException, SQLException ;
	public List<Notice> getNotices(int page, String field, String query) throws ClassNotFoundException, SQLException;
	
	@Delete("DELETE FROM notices WHERE seq  = #{ seq }")	
	public int delete(String seq) throws ClassNotFoundException, SQLException;	
	public int update( Notice notice ) throws ClassNotFoundException, SQLException;
	public Notice getNotice(String seq) throws ClassNotFoundException, SQLException;
	public int insert(Notice notice) throws ClassNotFoundException, SQLException ;
	
	// 트랜잭션 테스트 용도의 메서드 추가 -> NLMemberShipService 클래스 분리
	//public void insertAndPointUpOfMember(Notice notice, String id) throws ClassNotFoundException, SQLException;
	
	// 트랜잭션 격리성을 테스트 용도 메서드 추가 
	public void hitUp( String seq); 
	public int getHit( String seq);
	
} // class

 

 

5️⃣CustomerController

package org.doit.web.controllers;

import java.io.File;
import java.io.FileInputStream;
import java.security.Principal;
import java.util.List;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.ibatis.session.SqlSession;
import org.doit.web.newlecture.dao.NoticeDao;
import org.doit.web.newlecture.service.MemberShipService;
import org.doit.web.newlecture.vo.Notice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

@Controller
@RequestMapping("/customer/*")
public class CustomerController {

	//@Autowired
	//private NoticeDao noticeDao;
	
	@Autowired
	private SqlSession sqlSession;
	
	@Autowired
	private MemberShipService memberShipService;

	// 디폴트 생성자
	public CustomerController( ) {
		super(); 
	}
	// 생성자 1
	public CustomerController(NoticeDao noticeDao) {
		super();
		//this.noticeDao = noticeDao;
	} 
	//  getter, setter
	/*
	public NoticeDao getNoticeDao() {
		return noticeDao;
	}
	public void setNoticeDao(NoticeDao noticeDao) {
		this.noticeDao = noticeDao;
	}
	*/
	
    // [p287 ]
	// 20/noticePathVariable.htm
	// 30/noticePathVariable.htm
	@RequestMapping("members/{seq}/{deptno}/noticePathVariable.htm")
	public String noticePathVariable(
			@PathVariable("seq") String seq
			, @PathVariable("deptno") int deptno
			, HttpServletRequest request) throws Exception{
		System.out.println("> seq : " + seq +" , deptno : " + deptno);
		return "redirect:/customer/notice.htm";
	}	
	
	// 컨트롤러 메서드 선언
	// download.htm
	//?
    //p=customer/upload    경로
	//&
	//f=다운로드할 파일명
	@RequestMapping("download.htm")
	public void download (
			  HttpServletResponse response
			  , HttpServletRequest request
			  , @RequestParam("p") String p
			  , @RequestParam("f") String f
			) throws Exception{
		
		// 이창익(서버)     ->       함세강(클라이언트 즉, 브라우저)
		//  아이스크림     응답 ->     먹었다. 
		// 표지 [ 상자 :아이스크림 ]   응답 ->     X   저장 대화상자 띄운다.
		// 응답 헤드 X
		
		String fname =  f;  
		response.setHeader("Content-Disposition","attachment;filename="+ new String(fname.getBytes(), "ISO8859_1"));		
		 
		//String fullPath = request.getServletContext().getRealPath(	p + "/" + fname);
		String fullPath = request.getSession().getServletContext().getRealPath(	p + "/" + fname);
	 
		FileInputStream fin = new FileInputStream(fullPath);
		ServletOutputStream sout = response.getOutputStream(); // 응답 스트림
		byte[] buf = new byte[1024];
		int size = 0;
		while((size = fin.read(buf, 0, 1024)) != -1) {
			sout.write(buf, 0, size); 
		}
		fin.close();
		sout.close();
		
	} // download

	@RequestMapping("noticeDel.htm")
	public String noticeDel(			String seq , String filesrc  , HttpServletRequest request			) throws Exception {
		// 1. 첨부파일이 있을 경우엔 첨부파일을 upload 폴더 삭제
		// 서버 배포 실제 경로
		String uploadRealPath =   request.getSession().getServletContext().getRealPath("/customer/upload");

		/* [1] 첨부파일을 select 알아야 왔다.
		Notice notice = this.noticeDao.getNotice(seq);
		String filesrc = notice.getFilesrc();
		if( filesrc != null ) {
			File delFile = new File( uploadRealPath , filesrc);
			delFile.delete();
		}
		 */

		File delFile = new File( uploadRealPath , filesrc);
		if( delFile.exists() ) {
			delFile.delete();
		}

		// 2. 
		// int rowCount = this.noticeDao.delete(seq);
		NoticeDao mybatisNoticeDao  = this.sqlSession.getMapper( NoticeDao.class );
		int rowCount = mybatisNoticeDao.delete(seq);
		
		if( rowCount == 1 ) 		return "redirect:notice.htm";
		else return "redirect:noticeDetail.htm?seq="+seq;
	} // notices	


	//       /customer/noticeEdit.htm?seq=1  
	@RequestMapping( value = {"noticeEdit.htm"}, method = RequestMethod.GET )
	public String noticeEdit( String seq , Model model) throws Exception {

		// Notice notice = this.noticeDao.getNotice(seq);
		NoticeDao mybatisNoticeDao  = this.sqlSession.getMapper( NoticeDao.class );
		Notice notice = mybatisNoticeDao.getNotice(seq);
		
		model.addAttribute("notice", notice);

		// return "noticeEdit.jsp";	 
		return "customer.noticeEdit";
	} // noticeEdit	

	// /customer/noticeEdit.htm?seq=2 + POST 파라미터 ( title, content )
	@RequestMapping( value = {"noticeEdit.htm"}, method = RequestMethod.POST )
	public String noticeEdit(  
			Notice notice   // 커맨드 객체   =  수정된 제목, 내용 + 새로 추가된 첨부파일
			, @RequestParam("o_filesrc") String ofilesrc
			, HttpServletRequest request
			) throws Exception {
		// 첨부된 파일      O  => upload폴더 저장 + notice.setFilesrc("새로 첨부된 파일명");
		//    "                  X                X                               원래 filesrc 유지

		// 1. 첨부된 파일의  유무 확인 후에 파일 저장.
		CommonsMultipartFile multipartFile = notice.getFile();   
		
		String uploadRealPath = request.getSession().getServletContext().getRealPath("/customer/upload");
		
		if( !multipartFile.isEmpty() ) {  // 첨부된 파일이 있다면 
			
			// 원래 첨부된 파일 삭제.
			File delFile = new File( uploadRealPath , ofilesrc);
			if( delFile.exists() ) {
				delFile.delete();
			} 
			
			String  originalFilename= multipartFile.getOriginalFilename();  
			String filesystemName = getFileNameCheck(uploadRealPath, originalFilename); 
			File dest = new File(  uploadRealPath, filesystemName);
			multipartFile.transferTo(dest);  
			String filesrc = filesystemName;
			notice.setFilesrc(filesrc);
		} else {
			notice.setFilesrc(ofilesrc);
		}

		// 2.  수정된 제목, 내용 만 update
		// int rowCount = this.noticeDao.update(notice);   // title, content
		NoticeDao mybatisNoticeDao  = this.sqlSession.getMapper( NoticeDao.class );
		int rowCount = mybatisNoticeDao.update(notice);
		
		if (rowCount==1) {
			return "redirect:noticeDetail.htm?seq=" + notice.getSeq();	
		} else {
			return "redirect:noticeDetail.htm?seq=" + notice.getSeq()+"&error";
		}   

	} // noticeEdit	


	// doGet()/ doPost()        
	// request.getMethod()  GET/POST 확인 
	@RequestMapping( value = {"noticeReg.htm"}, method = RequestMethod.GET )
	public String noticeReg(  ) throws Exception {  
		
		// return "noticeReg.jsp";	 
		return "customer.noticeReg";
	} // noticeReg	


	@RequestMapping( value = {"noticeReg.htm"}, method = RequestMethod.POST)
	public String noticeReg(  
			Notice notice
			, HttpServletRequest request
			, Principal principal
			) throws Exception {   // 커맨드 객체
		// 1. 첨부된 파일의  유무 확인 후에 파일 저장.
		CommonsMultipartFile multipartFile = notice.getFile();  // getter

		// 서버 배포 실제 경로
		String uploadRealPath = null;

		if( !multipartFile.isEmpty() ) {  // 첨부된 파일이 있다면

			uploadRealPath = request.getSession().getServletContext().getRealPath("/customer/upload");
			System.out.println("> uploadRealPath : " + uploadRealPath);

			String  originalFilename= multipartFile.getOriginalFilename(); // 함세강   "a.txt"       -> a_1.txt
			String filesystemName = getFileNameCheck(uploadRealPath, originalFilename);

			File dest = new File(  uploadRealPath, filesystemName);
			multipartFile.transferTo(dest); // 파일을 저장

			// originalFilename, filesystemName Notices테이블의 컬럼이 2개 존재
			String filesrc = filesystemName;
			notice.setFilesrc(filesrc);
		} // if


		// 2. Notices 테이블에 공지사항 INSERT
		// notice.setWriter("kenik");		
		
		// 인증받은 객체 정보 얻어와서 name을 얻어오면 될 것 같아요. 
		/*  [1]
		UserDetails user =    (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();		
		notice.setWriter(   user.getUsername() );
		*/
		
		notice.setWriter( principal.getName() );
		
		/* 트랜잭션 테스를 위해서 주석 처리한 부분
		int rowCount = this.noticeDao.insert(notice);
		if( rowCount == 1 ) {  
			return "redirect:notice.htm";
		}else {
			return "noticeReg.jsp?error";  
		}
		*/
		
		
		// 트랜잭션 처리가 필요...
		// this.noticeDao.insertAndPointUpOfMember(notice, "kenik");
		this.memberShipService.insertAndPointUpOfMember(notice, principal.getName());
		
		 return "redirect:notice.htm"; 
	} // noticeReg	

	// 11:25 수업 시작
	// a.txt     /upload 저장
	// a-3.txt
	private String getFileNameCheck(String uploadRealPath, String originalFilename) {
		int index = 1;		
		while( true ) {			
			File f = new File(uploadRealPath, originalFilename);			
			if( !f.exists() ) return originalFilename;			
			// upload 폴더에 originalFilename 파일이 존재한다는 의미         asdfasf.txt (4자리)
			String fileName = originalFilename.substring(0, originalFilename.length() - 4 );  //   asdfasf
			String ext =  originalFilename.substring(originalFilename.length() - 4 );  // .txt
			// asdfasf-3.txt
			originalFilename = fileName+"-"+(index)+ext;

			index++;
		} // while 
	}
	/**
	// [1]
	// ?title=xxxx&content=yyyy
	@RequestMapping( value = {"noticeReg.htm"}, method = RequestMethod.POST)
	public String noticeReg(  Notice notice   ) throws Exception {   // 커맨드 객체

		notice.setWriter("kenik");

	    int rowCount = this.noticeDao.insert(notice);
	    if( rowCount == 1 ) {  
	    	return "redirect:notice.htm";
	    }else {
	    	return "noticeReg.jsp?error";  
	    }
	} // noticeReg	
	 */

	/*
	//   제목 title , 내용 content
	// [1]
	@RequestMapping( value = {"noticeReg.htm"}, method = RequestMethod.POST)
	public String noticeReg( String title, String content) throws Exception {  

		// String title = request.getParameter("title");
		Notice notice = new Notice();

		notice.setWriter("kenik"); // 로그인 한  아이디
		notice.setTitle(title);
		notice.setContent(content);

	    int rowCount = this.noticeDao.insert(notice);

	    if( rowCount == 1 ) {
	    	// 리다이렉트   :  공지사항 목록
	    	// JSP : 리다이렉트   -    response.sendRedirect("list.do");
	    	// 스프링에서 리다이렉트 ?                           redirect: 접두어를 붙인다.
	    	return "redirect:notice.htm";
	    }else {
	    	return "noticeReg.jsp?error"; // 글쓰기 페이지로 이동할 때 ?error 있으면 글쓰기 실패하고 다시 왔다. 
	    }
	} // noticeReg	
	 */

	/*
	[1]
	// noticeReg  컨트롤러 메서드 선언 + GET 방식
	@RequestMapping("noticeReg.htm")
	public String noticeReg( HttpServletRequest request  ) throws Exception {  
		String requestMethod = request.getMethod();  // GET,   POST
		if(requestMethod.equals("GET" )) {
			return "noticeReg.jsp";	
		}else {
			return null;
		} 

	} // noticeReg	
	 */
	// [3]
	//   /customer/notice.htm?page=1&field=title&query=hh
	@RequestMapping("notice.htm")
	public String notices(
			// ?page=1&field=title&query=hh
			@RequestParam( value = "page", defaultValue = "1" )  int page
			, @RequestParam( value = "field", defaultValue = "title" )  String field
			, @RequestParam( value = "query", defaultValue = "" )  String query
			, Model model
			) throws Exception { 

		
		// NLNoticeDao 사용
		//List<Notice> list=  this.noticeDao.getNotices( page, field, query);
		NoticeDao mybatisNoticeDao  = this.sqlSession.getMapper( NoticeDao.class );
		List<Notice> list=   mybatisNoticeDao.getNotices(page, field, query);
		
		model.addAttribute("list", list);  
		model.addAttribute("test", "Hello, Spring MVC World!");

		// return "notice.jsp";
		return "customer.notice";  // 스프링 타일즈 뷰리절브

	} // notices	

	/*
	// [2]
	//   /customer/notice.htm?page=1&field=title&query=hh
	@RequestMapping("notice.htm")
	public ModelAndView notices(
			// ?page=1&field=title&query=hh
			  String page
			, String field
			, String query

			, HttpServletRequest request
			, HttpServletResponse response) throws Exception { 

		int _page = 1;
		String _field = "title", _query="";

		if ( page != null && !page.equals("") ) {			_page = Integer.parseInt( page );		}
		if ( field != null && !field.equals("") ) {			_field = field;		}
		if ( query != null && !query.equals("") ) {			_query = query;		}

		ModelAndView mv = new ModelAndView();
		mv.addObject("test", "Hello, Spring MVC World!"); 
		List<Notice> list=  this.noticeDao.getNotices(_page, _field, _query);
		mv.addObject("list", list); 
		mv.setViewName("notice.jsp");  
		return mv;

	} // notices	
	 */

	/*
	[1]
	// 공지사항 목록 [컨트롤러 메서드]    <-    NoticeController.java
	@RequestMapping("notice.htm")
	public ModelAndView notices( 
			  HttpServletRequest request
			, HttpServletResponse response) throws Exception {

		String ppage = request.getParameter("page");
		String pfield = request.getParameter("field");
		String pquery = request.getParameter("query");

		int page = 1;
		String field = "title", query="";

		if ( ppage != null && !ppage.equals("") ) {			page = Integer.parseInt( ppage );		}
		if ( pfield != null && !pfield.equals("") ) {			field = pfield;		}
		if ( pquery != null && !pquery.equals("") ) {			query = pquery;		}

		ModelAndView mv = new ModelAndView();
		mv.addObject("test", "Hello, Spring MVC World!"); 
		List<Notice> list=  this.noticeDao.getNotices(page, field, query);
		mv.addObject("list", list); 
		mv.setViewName("notice.jsp");  
		return mv;

	} // notices	
	 */

	
	@RequestMapping("noticeDetail.htm")
	public String noticeDetail(
			Model model
			, HttpSession session
			, String seq    // ?seq=1
			) throws Exception { 
		
		NoticeDao mybatisNoticeDao  = this.sqlSession.getMapper( NoticeDao.class );
		
		// this.noticeDao.hitUp(seq);  // 조회수 증가  
		// Notice notice = this.noticeDao.getNotice(seq);
		mybatisNoticeDao.hitUp(seq);  // 조회수 증가  
		Notice notice = mybatisNoticeDao.getNotice(seq);
		
		model.addAttribute("notice", notice);
	
		// return "noticeDetail.jsp";
		return "customer.noticeDetail";  // View Name    ???.jsp X
	}
	
	/* [2]
	// p 356 컨트롤러 메서드의 파라미터 타입 + 리턴타입 
	// /customer/noticeDetail.htm?seq=1
	@RequestMapping("noticeDetail.htm")
	public String noticeDetail(
			Model model
			, HttpSession session
			, String seq    // ?seq=1
			) throws Exception { 

		// session.getAttribute("logonID");		
		// String seq = request.getParameter("seq");  X

		Notice notice = this.noticeDao.getNotice(seq); 
		model.addAttribute("notice", notice);

		return "noticeDetail.jsp";
	}
	*/

	/*
	[1]
	// 공지사항 상세 컨트롤러 메서드     <-    NoticeDetailController.java
	@RequestMapping("noticeDetail.htm")
	public ModelAndView noticeDetail(
			HttpServletRequest request
			, HttpServletResponse response) throws Exception { 
		String seq = request.getParameter("seq"); 
		Notice notice = this.noticeDao.getNotice(seq); 
		ModelAndView mv = new ModelAndView();
		mv.addObject("notice", notice);
		mv.setViewName("noticeDetail.jsp"); 
		 return mv;
	}
	 */

} // class

 

 

 

Comments