spring 로그인/로그아웃, 파일업로드

brave_chicken·2024년 5월 13일

잇(IT)생 챌린지

목록 보기
46/90

과제풀이 밑작업(db)

https://blog.naver.com/heaves1/223443077614

db코드

CREATE TABLE schedule(
	scheduleId varchar2(10) PRIMARY KEY,
	scheduleUserId varchar2(20) CONSTRAINT schedule_fk REFERENCES MEMBER(id),
	scheduleDay date,
	title varchar2(50),
	category varchar2(20),
	boss varchar2(20),
	place varchar2(50),
	content varchar2(50)
);

이미만든사람 추가 수정코드

Date를 변환해서 넘겨야 400번에러가 뜨지않음

기타

  • showpage만 하는건 서비스메소드 작업안하고 뷰호출만 가능
  • 과제는 CLRUD하는거 연습
  • 스케줄서비스 수정

스프링제공 로그인로그아웃

http://localhost:8089/erp/index.do

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
	<definition name="menu/sales" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/sales_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/emp/mypage.jsp"/>
	</definition>
	<definition name="menu/insa" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/insa_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/emp/mypage.jsp"/>
	</definition>
	<definition name="menu/it" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/it_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/emp/mypage.jsp"/>
	</definition>
	<definition name="menu/manage" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/manage_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/emp/mypage.jsp"/>
	</definition>
	<definition name="menu/jaemu" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/jaemu_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/emp/mypage.jsp"/>
	</definition>
	<definition name="menu/pub" extends="mainTemplate">
		<put-attribute name="menu" 
				value="/WEB-INF/menu/pub_menu.jsp"/>
		<put-attribute name="content" 
				value="/WEB-INF/include/content.jsp"/>
	</definition>
</tiles-definitions>

뷰에서 액션주소 변경


멤버컨트롤러 세션에 저장된거 뭔지 다시 질문

member.xml수정

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.multi.erp.member">
	<select id="selectall" resultType="member">
		select * from member
	</select>
	<select id="login" resultType="member" parameterType="member">
		select m.*, d.deptname, j.menupath, j.job_category 
		from member m, dept d, job j
		where id=#{id} and pass=#{pass}
				and m.deptno = d.deptno
				and d.job_category = j.job_id
	</select>
</mapper>




member.xml 수정 전 DTO 찍어보기

------------로그인한 사용자정보:MemberDTO [id=881011kim, pass=1234, name=김동현, ssn=721012-1111111, birthday=1990-11-11 00:00:00.0, marry=1, gender=1, position=과장, duty=팀장, classes=4급20호봉, startday=2010-10-01, endday=null, deptno=d006, curstate=재직, zipcode=222-222, addr=서울시 봉천구, detailaddr=좋은동네, phonehome=02-858-1111, phoneco=02-858-1111, phonecell=010-111-4444, email=jang@naver.com, profile_photo=kimdong.jpg, deptname=null, menupath=null, job_category=null, userImage=null]

member.xml 수정 후 DTO 찍어보기

------------로그인한 사용자정보:MemberDTO [id=881011kim, pass=1234, name=김동현, ssn=721012-1111111, birthday=1990-11-11 00:00:00.0, marry=1, gender=1, position=과장, duty=팀장, classes=4급20호봉, startday=2010-10-01, endday=null, deptno=d006, curstate=재직, zipcode=222-222, addr=서울시 봉천구, detailaddr=좋은동네, phonehome=02-858-1111, phoneco=02-858-1111, phonecell=010-111-4444, email=jang@naver.com, profile_photo=kimdong.jpg, deptname=총무과, menupath=/menu/manage_menu.jsp, job_category=경영관리, userImage=null]

MemberServiceImpl 로그인메소드

@Service
public class MemberServiceImpl implements MemberService {
	private MemberDAO dao;
	
	@Autowired
	public MemberServiceImpl(MemberDAO dao) {
		super();
		this.dao = dao;
	}

	@Override
	public List<MemberDTO> getMemberList() {
		List<MemberDTO> memberlist = dao.getMemberList();
		return memberlist;
	}
    

	//DB에서 조회한 데이터를 가공
	//뷰이름을 수정 /menu/it_menu.jsp => /menu/it
	@Override
	public MemberDTO login(MemberDTO loginUser) {
		//loginUser는 사용자가 입력한 값이 저장된 dto(request용 DTO)이고,
		//user는 디비인증결과가 저장된 dto(response용 DTO)
		MemberDTO user = dao.login(loginUser);
		System.out.println("서비스=>"+user);
		//db에서 가져온 값에서 menupath를 가공해서 뷰의 이름으로 menupath에 다시 셋팅
		if(user!=null) {
			String menupath = user.getMenupath();
			menupath = menupath.substring(menupath.indexOf("/")+1, menupath.indexOf("_"));
			//잘라낸 문자열이 뷰의 이름이므로 다시 setter메소드를 호출해서 저장한다.
			user.setMenupath(menupath);
		}
		System.out.println("++++++++++=>"+user);
		return user;
	}
}

menupath.substring(menupath.indexOf("/")+1, menupath.indexOf("_"))
해당 코드는 자바스크립트나 자바에서 사용될 수 있는 문자열 처리 코드입니다. 여기서 menupath는 문자열이며, 이 문자열에서 첫 번째 /와 사이의 부분 문자열을 추출하는 것입니다.
여기서 substring() 메서드는 문자열의 일부를 반환합니다. 첫 번째 매개변수는 시작 인덱스이고, 두 번째 매개변수는 종료 인덱스입니다. indexOf() 메서드는 특정 문자열이나 문자의 인덱스를 반환합니다. 따라서 menupath.substring(menupath.indexOf("/")+1, menupath.indexOf("
"))은 첫 번째 / 다음에 오는 문자부터 첫 번째 _ 이전의 문자까지의 부분 문자열을 추출합니다.

서비스 메소드 처리하니까 밑처럼 로그인한 사람에 따라 그사람의 부서에 따른 메뉴화면이 변경됨(menu-tiles에서 구성한대로)


MemberDAOImpl

@Repository
public class MemberDAOImpl implements MemberDAO {
	SqlSession sqlSessionTemplate;
	
	@Autowired
	public MemberDAOImpl(SqlSession sqlSessionTemplate) {
		super();
		this.sqlSessionTemplate = sqlSessionTemplate;
	}

	@Override
	public List<MemberDTO> getMemberList() {
		return sqlSessionTemplate.selectList("com.multi.erp.member.selectall");
	}
	@Override
	public MemberDTO login(MemberDTO loginUser) {
		return sqlSessionTemplate.selectOne("com.multi.erp.member.login", loginUser);
	}
}

emp-tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
	<definition name="login" extends="mainTemplate">
	</definition>
	<definition name="member/list" extends="mainTemplate">
		<put-attribute name="menu" value="/WEB-INF/menu/insa_menu.jsp"/>
		<put-attribute name="content" value="/WEB-INF/emp/memberlist.jsp"/>
	</definition>
</tiles-definitions>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- MyBatis내부에서 사용할 DTO와 Mapper를 등록 -->
	<typeAliases>
		<typeAlias type="com.multi.erp.board.BoardDTO" alias="board"/>
		<typeAlias type="com.multi.erp.member.MemberDTO" alias="member"/>
		<typeAlias type="com.multi.erp.schedule.ScheduleDTO" alias="schedule"/>
	</typeAliases>
	<mappers>
		<mapper resource="mapper/board.xml"/>
		<mapper resource="mapper/member.xml"/>
		<mapper resource="mapper/schedule.xml"/>
	</mappers>
</configuration>

MemberController

  • @SessionAttributes("user")에서 user라는 것은 세션에 저장하는 어트리뷰트의 이름
  • 스프링 MVC프레임워크 내부에서 컨트롤러에서 user라는 이름으로 공유된 Model객체에 저장된 어트리뷰트를 찾아서 "user"라는 이름의 어트리뷰트가 있으면 이를 세션에도 저장해준다
@Controller
@RequestMapping("/member")
@SessionAttributes("user")
public class MemberController {
	private MemberService service;
	@Autowired
	public MemberController(MemberService service) {
		super();
		this.service = service;
	}
	@GetMapping("/list")
	public ModelAndView list() {
		ModelAndView mav = new ModelAndView("member/list");
		List<MemberDTO> memberlist = service.getMemberList();
		mav.addObject("memberlist", memberlist);
		return mav;
	}
	
//	로그인 - 기존방식
	@PostMapping("/login")
	public String login(MemberDTO loginUserInfo, Model model, HttpServletRequest request) {
		String view = "";
		MemberDTO user = service.login(loginUserInfo);
		if(user!=null) {
			//로그인성공
			view = "redirect:/index.do";
			//세션에 로그인한 사용자의 데이터 공유
			HttpSession session = request.getSession();//세션만들기 - 로그인 성공하면 무조건 세션을 만든다.
			session.setAttribute("user", user);
		}else {
			//로그인실패
			view = "redirect:/emp/login.do";
		}
		return view;
	}
	
//	로그아웃 - 기존방식
	@GetMapping("/logout")
	public String logout(HttpSession session) {
		if(session!=null) {
			//사용하던 세션을 메모리에서 제거
			session.invalidate();
		}
		return "redirect:/index.do";
	}
	
//	스프링에서 제공되는 기능을 이용해서 로그인 처리하기
	@PostMapping("/spring/login")
	public String springlogin(MemberDTO loginUserInfo, Model model) {
		System.out.println("스프링이 제공하는 @SessionAttributes를 이용해서 로그인");
		MemberDTO user = service.login(loginUserInfo);
		System.out.println("------------로그인한 사용자정보:"+user);
		String view = "";
		if(user!=null) {
			//로그인성공
			model.addAttribute("user",user);
			view = user.getMenupath();//menu-tiles.xml에 등록한 이름의 뷰를 찾아서 뷰를 생성
		}else {
			//로그인실패
			view = "redirect:/emp/login.do";
		}
		return view;
	}
	
//	스프링에서 제공되는 기능을 이용해서 로그아웃 처리하기
//	내부에서 세션의 상태를 확인할 수 있도록
	@GetMapping("/spring/logout")
	public String springlogout(SessionStatus status) {
		System.out.println("스프링이 제공하는 @SessionAttributes를 이용해서 로그아웃");
		status.setComplete();//세션에 있는 객체(로그인한정보)를 제거
		return "redirect:/index.do";
	}
	
	//@SessionAttributes를 사용해서 세션에 저장된 데이터를 관리하는 경우
	//@ModelAttribute("user")는 모델데이터를 메소드의 매개변수에 매핑할때 사용
	//=>모델이나 세션에 저장되어있는 어트리뷰트를 메소드의 매개변수에 바인딩
	//user라는 이름으로 세션에 저장되어 있는 객체가 메소드의 매개변수에 매핑
	@GetMapping("/mypage")
	public String mypage(@ModelAttribute("user") MemberDTO user) {
		//로그인한 사용자의 mypage로 이동 - mypage는 menupath를 꺼내서 forward
		//로그인한 사용자의 정보는 세션에 저장
		System.out.println("로그인사용자=>"+user);
		return user.getMenupath();
	}
}

로그인은 아이디와 패스워드를 입력받아 유효한지 검증을 받는 코드가 포함
마이페이지는 로그인 완료 후에 내 페이지로 가고 싶은 경우 사용하는 기능
페이지가 동일한 뿐 실행 시점이나 실행흐름은 모두 다름
로그인은 최초 한 번만 하지만 다른 페이지를 탐색하다가 마이페이지 들어가고 싶은 경우 들어갈 수 있어야 하므로 마이페이지가 있어야 함

어트리뷰트명 변경, 액션 주소 변경


메뉴위에 잡카테고리 뜨게하기


미션

로그인 후 세션에 저장된 객체에서 값을 비교해서 내가 쓴 글만 수정과 삭제가 보이도록 처리하세요
boardlist.jsp
board_read.jsp처리하기

boardlist에서 <c:if>로 로그인시 작성자일때만 삭제버튼 출력되게 설정

태그립 등록

board_read에서 수정과 삭제는 위와 동일하게 설정

  • 로그인한번하면 user가 세션에 저장되도록 해놨기때문에 로그아웃할때까지 쓸수있음
  • 리퀘스트는 들어갔다가 나오면 클리어되고 세션은 들어갔다나왔다해도 항상 저장되어있다는 차이점

[파일업로드]

1단계 - 설정

1) 라이브러리 등록

  • 메이븐 중앙저장소에서 검색해서 사용
  • pom.xml에 라이브러리등록

2) 스프링 설정파일에 등록

  • CommonsMultipartResolver를 spring-config.xml에 등록
    -> id는 무조건 multipartResolver로 등록해야한다.
    -> spring mvc내부에서 multipartResolver로 등록된 빈을 찾아서 파일업로드를 처리
    -> enctype="multipart/form-data"로 처리하고 CommonsMultipartResolver의 id를 다르게 등록하면 파일과 폼데이터를 읽어올 수 없다.

3) 업로드될 파일이 저장될 폴더를 생성

2단계 - 파일업로드처리

  • 실제 업로드되는 서버의 위치가 필요
  • 업로드된 원본파일명과 중복되지 않도록 식별할 수 있는 파일명을 생성해서 업로드하기
  • 파일업로드와 폼데이터가 같이 서버로 전송되어야 하므로 (요청방식이 전혀다름) 무조건 enctype="multipart/form-data"로 전송해야하고 method="post"로 정의해야 한다.

HTML폼 전송 방식
(1) enctype="application/x-www-form-urlencoded"
-> 폼데이터를 name=value&name=value...의 형태로 전송하라는 의미
-> HTML폼 데이터를 서버로 전송하는 가장 기본적인 방식
-> 별도로 enctype설정을 정의하지 않으면 request헤더에 application/x-www-form-urlencoded로 전송되었음이 추가
-> 입력한 데이터는 요청메시지의 body에 name=value&name=value...의 형식으로 전송
입력한 파라미터와 파라미터는 &기호로 구분된다.

  • 사용자가 입력한 데이터와 업로드할 파일에 대한 정보를 같이 받아서 처리할 수 있도록 작업
    스프링MVC에서 클라이언트가 입력한 데이터를 객체로 만들어서 컨트롤러에 전송
    -> 객체 (DTO)
    스프링 MVC에서 업로드되는 파일을 MultipartFile로 관리
    업로드되는 파일을 받아서 처리하기 위해서 DTO에 멤버변수로 정의
    멤버변수명은 html태그에 정의된 name과 동일
    업로드하는 파일이 여러개인 경우 spring mvc List로 관리하거나 ultipartFile[]로 만들어서 넘겨준다.

3단계 - 업로드되는 정보가 디비에 저장

4단계 - 파일다운로드

파일업로드 실습

pom.xml에 추가

		<!-- 파일업로드 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.4</version>
		</dependency>

spring-config에 등록

<!--===============================파일업로드==============================  -->
	<beans:bean id="multipart" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="maxUploadSize" value="4000000"/>
	</beans:bean>

WEB-INF에 upload 폴더 만듦

  • 이 위치는 작업하기 편한위치고 실제서버가 인식하는 위치는
    C:\backend23\work\springwork.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\erp\WEB-INF
  • 사이즈를 최소화해서 원하는 해상도 구현할지 생각해야 함

보드write에 파일업로드 뷰 추가

  • 글내용이랑 파일이랑 다른 위치에 저장되어야함
  • 파일을 한두명이 업로드할게 아니니 파일명이 중복되지 않게 만들어야함
  • 파일업로드는 무조건 포스트방식. 겟방식은 256메가?까지밖에안됨

BoardController @PostMapping("/write")이부분 수정해서 파일업로드할수있게

@Controller
@RequestMapping("/board")
public class BoardController {
	private BoardService service;
	private FileUploadService fileuploadService;
	@Autowired
	public BoardController(BoardService service, FileUploadService fileuploadService) {
		super();
		this.service = service;
		this.fileuploadService = fileuploadService;
	}

	@GetMapping("/write")
	public String write() {
		return "board/writepage";//뷰이름
	}
	//게시글등록을 위해 사용자가 입력한 내용과 첨부한 파일이 업로드되도록 처리
	@PostMapping("/write")
	public String insert(BoardDTO board, HttpSession session) 
								throws IllegalStateException, IOException {
		System.out.println("파일업로드:"+board);
		//1. MultipartFile 정보를 추출
		List<MultipartFile> file = board.getFiles();
		//2. 업로드될 서버의 실제 위치를 추출
		//	- 실제 서버에서 인식하는 업로드된 파일이 저장될 폴더의 경로를 추출하기
		//	- context내부에 있으므로 ServletContext객체를 잉ㅇ
		//	- ServletContext객체는 프로젝트(context)에 대한 정보를 담고 있는 객체이고 
		//		이 안에 실제 경로를 구할 수 있는 기능이 있음
		//	- ServletContext는 세션객체를 통해 생성
		String path = WebUtils.getRealPath(session.getServletContext(), "/WEB-INF/upload");
		System.out.println("^^^^^^"+path);
		service.insert(board);
		
		//3. 업로드 로직을 처리하는 서비스의 메소드를 호출
		fileuploadService.uploadFiles(file, path);
		return "redirect:/board/list?category=all";
	}
}

FileUploadService

  • 파일업로드를 수행하는 메소드 - 파일업로드를 하기 위해서 List< MultipartFile >객체와 실제 업로드할 위치를 매개변수로 전달받아 사용
@Service
public class FileUploadService {
	public void uploadFiles(List<MultipartFile> multipartFiles, String path) 
								throws IllegalStateException, IOException {
		for(MultipartFile multipartFile:multipartFiles) {
			//파일명
			String filename = multipartFile.getOriginalFilename();
			//~~~~/WEB-INF/upload + / + 파일명
			//-------------------
			//		path
			multipartFile.transferTo(new File(path+File.separator+filename));
		}
	}
}

board_write.jsp enctype수정추가

BoardDTO List files 추가

영구적으로 저장되게하려면 무조건 db에 저장해야함

추가 다하면 실제 파일경로에 파일 업로드한 파일 들어옴. 그러나 동일한파일이 반복해서 들어오지않음

이미지파일업로드를 위한 준비작업
파일업로드

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글