반응형

프로젝트 생성하기!

 

 

 

[ JSP 환경설정 ]

pom.xml에 JSP library를 넣어줍니다.

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>


        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet.jsp.jstl</groupId>
            <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>jakarta.servlet.jsp.jstl</artifactId>
            <version>3.0.1</version>
        </dependency>

 

 

spring.application.name=demo_photo

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

 

 

Mybatis 환경도 추가해준다. (MySQL도 포함)

#Mapper Camel & Snake 표기법 지원여부를 true로 줄 시에, my_name이라는 column명이 myName으로 변경되어 해석을 하게 된다.

 
#MySql DataSource
spring.datasource.username: test
spring.datasource.password: test
spring.datasource.url: jdbc:mysql://localhost:3306/mydb?&serverTimezone=UTC&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=: com.mysql.cj.jdbc.Driver


#Mapper Camel & Snake표기법 지원여부 : my_name -> String my_name : ...camel-case=false
#                                      my_name -> String myName  : ...camel-case=true
# mybatis.configuration.map-underscore-to-camel-case=false

#Model Location
mybatis.type-aliases-package=com.githrd.demo_photo.vo
#Xml Location
mybatis.mapper-locations=classpath:mappers/*.xml

 

기존 파일 이 경로 그대로 가져오기

 

 

포토DB.sql
0.00MB
회원DB.sql
0.00MB

 

 

해당 DB를 파일에 넣어주자

 

MySQL문으로 이제 본격적으로 변경해보겠다.

 

sequence 없앴고, 문자형, 날짜형 타입 변경

 

primary key는 이름을 지정해줘도 MySQL에서는 이름이 나오는 것이 아니라, primary key로 저장이 되기 때문에, table을 생성할 때 그냥 그대로 primary key를 적용해준다.

 

 

 

/*


-- 회원테이블
create table member
(
   mem_idx   	int primary key auto_increment,	-- 회원번호
   mem_name  	varchar(100) not null,			    -- 회원명
   mem_id    	varchar(100) not null,			    -- 아이디
   mem_pwd   	varchar(100) not null,			    -- 비밀번호
   mem_zipcode 	char(5)     not null,			    -- 우편번호
   mem_addr  	varchar(1000) not null,		      -- 주소
   mem_ip    	varchar(100) not null,			    -- 아이피
   mem_regdate 	datetime  default now(),		  -- 가입일자
   mem_grade 	varchar(100) default '일반' 	  -- 회원등급
)

-- 아이디(unique)
alter table member
  add constraint unique_member_id unique(mem_id);

-- 회원등급(check)
alter table member
  add constraint ck_member_grade  check(mem_grade in('일반','관리자'));

-- sample data
insert into member values(null,
                          '김관리',
                          'admin',
                          'admin',
                          '00000',
                          '서울시 관악구',
                          '127.0.0.1',
                          sysdate(),
                          '관리자'
                          );
                          
insert into member values(null,
                          '일길동',
                          'one',
                          '1234',
                          '00000',
                          '서울시 관악구',
                          '127.0.0.1',
                          default,
                          default
                          );                          

-- JDBC에서 사용할 insert문
insert into member values(null,?,?,?,?,?,?,default,default)


select * from member where mem_id='one1'

*/

 

 

 

정상적으로 출력이 된다.

 

 

 

 

Photo DB도 넣어보자

/*

-- 테이블생성
create table photo
(
   p_idx	  int primary key auto_increment,		-- 일련번호
   p_title    varchar(200)  not null, 				-- 제목
   p_content  varchar(2000) not null,				-- 내용
   p_filename varchar(200) not null,   				-- 화일명
   p_ip       varchar(100)  not null,				-- 아이피
   p_regdate  datetime,								-- 등록일자
   mem_idx    int,									-- 회원번호
   mem_name   varchar(100)  not null				-- 회원명
)

-- 외래키
alter table photo
  add constraint fk_photo_mem_idx foreign key(mem_idx)
                                  references member(mem_idx)
                                  on delete cascade
                                  -- 부모삭제시-> 자식게시물도 삭제


*/

 

 

 

 

mapper 수정해서 넣기 + Dao 생성하기 (Mapper 이름과 동일하게 만들어야 한다)

 

[ Dao와 Mapper 이름 통일 ]

implement 안해주는 대신에, 이름을 통일 시켜야 한다.

 

 

Type alias Vo에서 지정해준다.

 

 

MemberMapper.xml의 namespace에 정확한 경로와 이름을 넣어준다.

 

 

resultType alias로 가져오기

 

 

반드시 mapper에서 맞춰주어야 하는것은 id와 MemberMapper에 들어가는 Method명을 동일시 해줘야 한다는 것이다.

 

 

sequence의 값을 null로 변경해준다(MySQL에서 auto_increment로 지정해주었기 때문이다)

<?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="com.githrd.demo_photo.dao.MemberMapper">

	<select id="selectList" resultType="member">
		select * from member order by mem_idx
	</select>
	
	<select id="selectOneFromIdx" resultType="member" parameterType="int">
		select * from member where mem_idx = #{ mem_idx }
	</select>
	
	<select id="selectOneFromId" resultType="member" parameterType="String">
		select * from member where mem_id = #{ mem_id }
	</select>
	
	<insert id="insert" parameterType="member">
		insert into member values(
			                      null,
			                      #{ mem_name },
			                      #{ mem_id },
			                      #{ mem_pwd },
			                      #{ mem_zipcode },
			                      #{ mem_addr },
			                      #{ mem_ip },
			                      default,
			                      default
			                      )
	</insert>
	
	<delete id="delete" parameterType="int">
		delete from member where mem_idx= = #{ mem_idx }
	</delete>
	
	<update id="update" parameterType="member">
		update member set mem_name = #{ mem_name },
		                  mem_id = #{ mem_id },
		                  mem_pwd = #{ mem_pwd },
		                  mem_zipcode = #{ mem_zipcode },
		                  mem_addr = #{ mem_addr },
		                  mem_grade = default,
		                  where mem_idx = #{ mem_idx }
	</update>
	

</mapper>

 

 

 

package com.githrd.demo_photo.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.githrd.demo_photo.vo.MemberVo;

@Mapper
public interface MemberMapper {

    List<MemberVo> selectList();

    MemberVo selectOneFromIdx(int mem_idx);
    
    MemberVo selectOneFromId(String mem_id);

    int insert(MemberVo vo);

    int delete(int mem_idx);

    int update(MemberVo vo);

}

 

 

 

[ 위와 같이 Photo도 같이 적용시켜주자 ]

 

 

 

 

이런 부분은 MySQL문에서 오류가 발생되기 때문에 조심해야 합니다.

(alias type 지정, 예약어 중복)

 

 

 

<?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="com.githrd.demo_photo.dao.PhotoMapper">

	<select id="selectList" resultType="photo">
		select * from photo order by p_idx desc
	</select>
	
	<!-- Paging별 조회 -->
	<select id="selectPageList" parameterType="Map" resultType="photo">
		select * from
		(
			select
				rank() over(order by p_idx desc) as no,
				p.*
			from
				(select * from photo) p
		) pp
		where no between #{ start } and #{ end }
	</select>
	
	<!-- 전체레코드수 구하기 -->
	<!-- nvl => ifnull : 만약에 값이 null이면, -->
	<!-- select ifnull(null,0) from dual; -->
	<select id="selectRowTotal" resultType="int">
		select ifnull(count(*),0) from photo
	</select>
	
	<select id="selectOne" resultType="photo" parameterType="int">
		select * from photo where p_idx = #{ p_idx }
	</select>
	
	<insert id="insert" parameterType="photo">
		insert into photo values(
		                         null,
		                         #{ p_title },
		                         #{ p_content },
		                         #{ p_filename },
		                         #{ p_ip },
		                         now(),
		                         #{ mem_idx },
		                         #{ mem_name }
		                         )
	</insert>
	
	<update id="updateFilename" parameterType="photo">
		update photo set p_filename = #{ p_filename } where p_idx = #{ p_idx }
	</update>
	
	<update id="update" parameterType="photo">
		update photo set p_title = #{ p_title }, p_content = #{ p_content } where p_idx = #{ p_idx }
	</update>
	
	<delete id="delete" parameterType="int">
		delete from photo where p_idx = #{ p_idx }
	</delete>
	
	
	
	
	
	

</mapper>

 

 

 

package com.githrd.demo_photo.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;

import com.githrd.demo_photo.vo.PhotoVo;

@Mapper
public interface PhotoMapper {

    List<PhotoVo> selectList();

    List<PhotoVo> selectPageList(Map<String, Object> map);

    int selectRowTotal();

    PhotoVo selectOne(int p_idx);

    int insert(PhotoVo vo);

    int delete(int p_idx);

    int updateFilename(PhotoVo vo);

    int update(PhotoVo vo);

}

 

 

 

 

[ Mapper에 연결된 Controller 수정 ]

package com.githrd.demo_photo.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.tags.shaded.org.apache.xpath.operations.Bool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.githrd.demo_photo.dao.MemberMapper;
import com.githrd.demo_photo.vo.MemberVo;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

@Controller
@RequestMapping("/member/")
public class MemberController {
	
	// 자동연결
	@Autowired
	HttpServletRequest request;
	
	@Autowired
	HttpSession session;
	
	// 처음에 1회 연결
	@Autowired
	MemberMapper member_mapper;
	
	// class RequestMapping + method RequestMapping => /member/login_form.do
	@RequestMapping("login_form.do")
	public String login_form() {
		
		return "member/member_login_form";
	}
	
	// /member/login.do?mem_id=one&mem_pwd=1234
	@RequestMapping("login.do")
	public String login(String mem_id, String mem_pwd, RedirectAttributes ra) {
		
		MemberVo user = member_mapper.selectOneFromId(mem_id);
		
		// 로그인한 유저 정보가 없으면,
		if(user==null) {
			
			// RedirectAttributes에 redirect할 때 넘어가야할 정보를 알려주면
			// parameter로 이용된다.
			ra.addFlashAttribute("reason","fail_id");
			
			// return "redirect:login_from.do?reason=fail_id";
			return "redirect:login_from.do";
		}
		
		// 비밀번호가 틀린 경우
		if(user.getMem_pwd().equals(mem_pwd)==false) {
			//response.sendRedirect("login_form.do?reason=fail_pwd&mem_id=" + mem_id);
			ra.addAttribute("reason","fail_pwd");
			ra.addAttribute("mem_id",mem_id);
			
			return "redirect:login_form.do";
		}
		
		// 로그인 처리: 현재 로그인 객체(user)정보를 session 저장
		session.setAttribute("user", user);
		
		return "redirect:../photo/list.do";
	}
	
	
	// 로그아웃
	@RequestMapping("logout.do")
	public String logout() {
		
		session.removeAttribute("user");
		
		return "redirect:../photo/list.do";
	}
	
	@RequestMapping("modify_form.do")
	public String modify_form(int mem_idx, Model model) {
		
		MemberVo vo = member_mapper.selectOneFromIdx(mem_idx);
		
		model.addAttribute("vo", vo);
		
		return "member/member_modify_form";
	}
	
	@RequestMapping("modify.do")
	public String modify(int mem_idx, String mem_name, String mem_id, String mem_pwd, String mem_zipcode,
			String mem_addr, String mem_grade) {
		
		MemberVo vo = new  MemberVo(mem_idx, mem_name, mem_id, mem_pwd, mem_zipcode, mem_addr, mem_grade);
		
		member_mapper.update(vo);
		
		String mem_ip = request.getRemoteAddr();
		
		vo.setMem_ip(mem_ip);
		
		session = request.getSession();
		MemberVo loginUser = (MemberVo) session.getAttribute("user");
		
		if(loginUser.getMem_idx()==mem_idx) {
			
			// 로그인상태정보
			MemberVo user = member_mapper.selectOneFromIdx(mem_idx);
			
			// session.removeAttribute("user"); 불필요한 작업
			// scope내에 저장방식 Map형식: key / value
			//						  동일한 key로 저장하면 수정처리된다
			session.setAttribute("user", user);
		}
		
		return "redirect:list.do";
	}
	
	@RequestMapping("insert_form.do")
	public String insert_form() {
		
		return "member/member_insert_form";
	}
	
	@RequestMapping("insert.do")
	public String insert(String mem_name, String mem_id, String mem_pwd, String mem_zipcode,
			String mem_addr) {
		
		String mem_ip = request.getRemoteAddr();
		
		MemberVo vo = new MemberVo(mem_name, mem_id, mem_pwd, mem_zipcode, mem_addr, mem_ip);
		
		int res = member_mapper.insert(vo);
		
		return "redirect:../photo/list.do";
	}
	
	@RequestMapping(value="check_id.do")
	@ResponseBody
	public Map<String, Boolean> check_id(String mem_id) {
		
		MemberVo vo = member_mapper.selectOneFromId(mem_id);
		
		boolean bResult = (vo==null);

		Map<String, Boolean> map = new HashMap<String, Boolean>();
		map.put("result", bResult); // {"result" : true}
		
		return map;
	}
	
	@RequestMapping("list.do")
	public String list(Model model) {
		
		List<MemberVo> list = member_mapper.selectList();
		
		model.addAttribute("list",list);
		
		return "member/member_list";
	}
	
}

 

 

 

json으로 넘겨줄 필요없이 Spring Boot를 사용하고 있으면 PhotoVo로 객체를 받아버리면, 알아서 넘어가진다.

package com.githrd.demo_photo.controller;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.githrd.demo_photo.dao.PhotoMapper;
import com.githrd.demo_photo.util.MyCommon;
import com.githrd.demo_photo.util.Paging;
import com.githrd.demo_photo.vo.MemberVo;
import com.githrd.demo_photo.vo.PhotoVo;

import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

@Controller
@RequestMapping("/photo/")
public class PhotoController {
	
	@Autowired
	PhotoMapper photo_mapper;
	// ip 구하기 위해서 request 사용
	@Autowired
	HttpServletRequest request;
	// 절대 경로 구하기 위해서 application 사용
	@Autowired
	ServletContext application;
	// Session 전달용 session 사용
	@Autowired
	HttpSession session;
	
	// /photo/list.do?page=2
	@RequestMapping("list.do")
	public String list(@RequestParam(name="page",defaultValue = "1") int nowPage,
			Model model) {
		
		
		// 게시물의 범위 계산(start/end)
		int start = (nowPage-1) * MyCommon.Photo.BLOCK_LIST + 1;
		int end = start + MyCommon.Photo.BLOCK_LIST - 1;
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("start",start);
		map.put("end",end);
		
		
		List<PhotoVo> list = photo_mapper.selectPageList(map);
		
		// 전체 게시물수
		int rowTotal = photo_mapper.selectRowTotal();
		
		// pageMenu 만들기
		String pageMenu = Paging.getPaging("list.do",   // pageURL
											nowPage,    // 현재페이지
											rowTotal,   // 전체페이지
											MyCommon.Photo.BLOCK_LIST,  // 한화면에 보여질 게시물 수
											MyCommon.Photo.BLOCK_PAGE); // 한화면에 보여질 페이지 수
		
		// 결과적으로 request binding
		model.addAttribute("list",list);
		model.addAttribute("pageMenu",pageMenu);
		
		return "photo/photo_list";
	}
	
	
	@RequestMapping("insert_form.do")
	public String insert_form() {
		
		return "photo/photo_insert_form";
	}
	
	
	//사진등록
	//							요청 Parameter 이름과 받는 변수명이 동일하면 @RequestParam(name="")의
	//							name 속성은 생략가능
	@RequestMapping("insert.do")
	public String insert(PhotoVo vo,
			@RequestParam(name="photo") MultipartFile photo,
			RedirectAttributes ra) throws Exception {
		
		// 유저 정보 얻어오기
		MemberVo user = (MemberVo) session.getAttribute("user");
		
		// session timeout
		if(user==null) {
			
			// response.sendRedirect("../member/login_form.do?reason=session_timeout");
			ra.addAttribute("reason","session_timeout");
			return "redirect:../member/login_form.do";
		}
		
		// 파일 업로드 처리
		String absPath = application.getRealPath("/resources/images/");
		String p_filename = "no_file";
		
		if(!photo.isEmpty()) {
			
			// 업로드 파일이름 얻어오기
			p_filename = photo.getOriginalFilename();
			// 저장할 위치 + file 이름
			File f = new File(absPath,p_filename);
			
			if(f.exists()) { // 저장경로에 동일한 파일이 존재하면=>다른이름변경
				// 변경파일명 = 시간_원본파일명
				
				long tm = System.currentTimeMillis();
				p_filename = String.format("%d_%s", tm, p_filename);
				
				f = new File(absPath,p_filename);
			}
			
			// 임시 파일=>내가 지정한 위치로 복사
			photo.transferTo(f);
		}
		
		// 업로드 된 파일이름
		vo.setP_filename(p_filename);
		// IP
		String p_ip = request.getRemoteAddr();
		vo.setP_ip(p_ip);
		String p_content = vo.getP_content().replaceAll("\n", "<br>");
		vo.setP_content(p_content);
		
		// 입력한 로그인 유저 넣는다
		vo.setMem_idx(user.getMem_idx());
		
		vo.setMem_name(user.getMem_name());

		// DB Insert
		int res = photo_mapper.insert(vo);
		return "redirect:list.do";
	}
	
	@RequestMapping(value="photo_one.do",
			produces = "application/json;charset=utf-8;")
	@ResponseBody // 현재 반환값을 응답데이터를 이용해라
	public PhotoVo photo_one(int p_idx) {
		
		PhotoVo vo = photo_mapper.selectOne(p_idx);
		
		return vo;

		// VO -> JSON 객체 생성(필요없는건 안넘겨도 됨)
		// JSONObject json = new JSONObject();
		// json.put("p_idx", 		vo.getP_idx());
		// json.put("p_title",		vo.getP_title());
		// json.put("p_content", 	vo.getP_content());
		// json.put("p_filename", 	vo.getP_filename());
		// json.put("p_regdate",	vo.getP_regdate());
		// json.put("p_ip", 		vo.getP_ip());
		// json.put("mem_idx", 	vo.getMem_idx());
		// json.put("mem_name", 	vo.getMem_name());
		
		// return json.toString();
	}
	
	
	@RequestMapping("delete.do")
	public String delete(PhotoVo vo,int p_idx) {
		
		vo = photo_mapper.selectOne(p_idx);
		
		String absPath = request.getServletContext().getRealPath("/resources/images/");
		
		File delFile = new File(absPath, vo.getP_filename());
		delFile.delete();
		
		// DB delete
		int res = photo_mapper.delete(p_idx);
		
		return "redirect:list.do";
	}
	
	@RequestMapping("modify_form.do")
	public String modify_from(int p_idx, PhotoVo vo, Model model) {
		
		vo = photo_mapper.selectOne(p_idx);
		
		String p_content = vo.getP_content().replaceAll("<br>", "\n");
		vo.setP_content(p_content);
		
		model.addAttribute("vo", vo);
		
		return "photo/photo_modify_form";
	}
	
	@RequestMapping("modify.do")
	public String modify(int p_idx, String p_title, String p_content, PhotoVo vo) {
		
		vo.setP_idx(p_idx);
		vo.setP_title(p_title);
		vo.setP_content(p_content);
		
		photo_mapper.update(vo);
		
		return "redirect:list.do";
	}
	
	@RequestMapping(value="photo_upload.do",produces = "application/json;charset=utf-8")
	@ResponseBody
	public String upload(PhotoVo vo, MultipartFile photo, RedirectAttributes ra, int p_idx) throws Exception {
		
		String absPath = application.getRealPath("/resources/images/");
		
		String p_filename = "no_file";
		
		if(!photo.isEmpty() ) {
			
			p_filename = photo.getOriginalFilename();
			
			File f = new File(absPath,p_filename);
			
			if(f.exists()) {
				
				long tm = System.currentTimeMillis();
				p_filename = String.format("%d_%s", tm, p_filename);
				
				f = new File(absPath, p_filename);
			}
			
			photo.transferTo(f);
		}
		
		vo = photo_mapper.selectOne(p_idx);
		File delFile = new File(absPath, vo.getP_filename());
		delFile.delete();
		
		vo.setP_filename(p_filename);
		photo_mapper.updateFilename(vo);
		
		String json = String.format("{\"p_filename\":\"%s\"}", p_filename);
		
		return json;
	}
	
}

 

 

 

 

 

반응형

'데이터베이스↗' 카테고리의 다른 글

DBeaver 초보자드루와 사용방법  (1) 2024.08.28
MySQL vs Oracle SQL  (0) 2024.08.14
MySQL 사용기  (0) 2024.08.14
MySQL 설치 가이드 / 사용하기  (0) 2024.08.14
게시판 페이징 처리  (1) 2024.07.12