개발환경
- IntelliJ IDEA Community Edition
- amazon corretto open jdk 11
- mysql 8
- mybatis
- JSP
- Tomcat 9
주요 기능
- 회원가입
- 로그인
- 회원목록 출력
- 상세조회
- 수정
- 삭제
- ajax 이메일 중복체크
기존 기본 설정
인텔리제이 , 톰켓 서버 연결
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/"/>
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- 프로젝트 패키지이름 확인 -->
<context:component-scan base-package="com.codingrecipe.member" />
</beans:beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/root-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>member_framework</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>member_framework Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java-version>11</java-version>
<org.springframework-version>5.3.20</org.springframework-version>
<org.slf4j-version>1.7.25</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- data base -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.31</version>
</dependency>
<!-- fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- json -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<!-- jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>mvc_test</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
DB sql
-- 계정 생성하기
create database db_codingrecipe;
create user user_codingrecipe@localhost identified by '1234';
grant all privileges on db_codingrecipe.* to user_codingrecipe@localhost;
-- 회원 테이블
drop table if exists member_table;
create table member_table(
id bigint primary key auto_increment,
memberEmail varchar(20) unique,
memberPassword varchar(20),
memberName varchar(20),
memberAge int,
memberMobile varchar(30)
);
데이터 베이스 생성 쿼리문
회원 테이블 생성 쿼리문
DB 계정과 회원 테이블을 생성 합니다.
툴은 miria DB 를 사용하였습니다.
회원 가입 기능
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h2>hello spring framework 회원 프로젝트 입니다.</h2>
<a href="/member/save">회원가입</a>
<a href="/member/login">로그인</a>
<a href="/member/">회원목록 조회</a>
</body>
</html>
MemberController
package com.codingrecipe.member.controller;
import com.codingrecipe.member.dto.MemberDTO;
import com.codingrecipe.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import java.util.List;
@Controller
@RequestMapping("/member") // 공통 주소를 표현 그 이하의 주소를 메서드로 받아준다.
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
// @GetMapping("/member/save") // /member/member/save
@GetMapping("/save")
public String saveForm() {
return "save";
}
}
save.jsp - 회원 가입 페이지
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>save</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<form action="/member/save" method="post">
<input type="text" name="memberEmail" placeholder="이메일" id="memberEmail" onblur="emailCheck()">
<p id="check-result"></p>
<input type="text" name="memberPassword" placeholder="비밀번호">
<input type="text" name="memberName" placeholder="이름">
<input type="text" name="memberAge" placeholder="나이">
<input type="text" name="memberMobile" placeholder="전화번호">
<input type="submit" value="회원가입">
</form>
</body>
</script>
</html>
/member/save 로 post 방식으로
이름 비밀번호 전화번호 등 5가지 항목으로 보낸다.
회원가입 버튼을 누르면 submit 실행 되서 action url 이동
MemberDTO
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class MemberDTO {
private Long id; // 아이디
private String memberEmail; // 이메일
private String memberPassword; // 패스워드
private String memberName; // 이름
private int memberAge; // 나이
private String memberMobile; // 번호
}
클래스를 만든다
회원관련된 정보를 정의 한다.
회원가입을 받아줄때 전달하는 역할 + 조회정보를 화면에 보여주는 용도
회원과 관련된 모든 정보를 표현해줘야 한다.
필드명은 폼에서 전송하는 name 과 반드시 일치 해야한다.
대소문자가 틀리면 값이 담아 질수가 없다.
MemberController
package com.codingrecipe.member.controller;
import com.codingrecipe.member.dto.MemberDTO;
import com.codingrecipe.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import java.util.List;
@Controller
@RequestMapping("/member") // 공통 주소를 표현 그 이하의 주소를 메서드로 받아준다.
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
// @GetMapping("/member/save") // /member/member/save
@GetMapping("/save")
public String saveForm() {
return "save";
}
@PostMapping("/save")
public String save(@ModelAttribute MemberDTO memberDTO) {
int saveResult = memberService.save(memberDTO);
if (saveResult > 0) {
return "login";
} else {
return "save";
}
}
}
주소 요청하는 controller 주소를 만들려 가보자
회원가입 정보를 받아주는 메소드
DTO에 담겨있는 값은 DB가 된다.
멤버 서비스 클래스를 의존성 주입해서 활용할수 있도록 한다.
리턴값에 따라 가입 성공 실패 여부를 확인 할 수 있다.
memberService
package com.codingrecipe.member.service;
import com.codingrecipe.member.dto.MemberDTO;
import com.codingrecipe.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
public int save(MemberDTO memberDTO) {
return memberRepository.save(memberDTO);
}
}
@RequiredArgsConstructor 롬복 어노테이션을 사용
final MemberRepository 에서
final 이 붙은 필드를 가진 생성자를 만든다. 생성자 주입 이라고 표현 한다.
Repository 클래스
package com.codingrecipe.member.repository;
import com.codingrecipe.member.dto.MemberDTO;
import lombok.RequiredArgsConstructor;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final SqlSessionTemplate sql;
public int save(MemberDTO memberDTO) {
System.out.println("memberDTO = " + memberDTO);
return sql.insert("Member.save", memberDTO);
}
}
DB와 연관된 클래스 , 마이바티스에 기능별로 쿼리 정리 적절한 쿼리들을 호출해주고 매개변수가 있다면 넘겨주면 리턴값이 있으면 리턴해주는 주된 역할을 해준다
매개변수로 넘겨주고 있는 값이 전달되어 있는지 확인
마이바티스에서 제공하는 SqlSessionTemplate 객체로 접근해서
CRUD 를 위한 메서드를 제공해준다.
DB에 값을 넣는 insert 를 사용한다.
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 데이터베이스 이름 및 계정 확인 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_codingrecipe?useSSL=false&serverTimezone=Asia/Seoul" />
<property name="username" value="user_codingrecipe"/>
<property name="password" value="1234"/>
</bean>
<!-- 파일 모두 생성했는지 확인 Mapper 에 대한 위치를 지정한다. (위치 참조) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value ="classpath:/mybatis-config.xml" />
<property name="mapperLocations" value="classpath:/mapper/*.xml" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8" />
<property name="maxUploadSize" value="10000000" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
DB와 관련된 세팅 , 파일업로드(게시판할때 쓸것입니다) 코드
<property name="url" value="jdbc:mysql://localhost:3306/db_codingrecipe?useSSL=false&serverTimezone=Asia/Seoul" /> 테이블 스페이스 이름 을 지정
계정과 정보를 입력한다.
이러한 정보들이 스프링 빈으로 등록되면서 서로 간에 연계되면서 서로를 호출되서 등록 된다.
Repository 에서 Mybatis를 이용해서 db쿼리를 보낼수 있게 된다.
resources 폴더 - Mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.codingrecipe.member.dto.MemberDTO" alias="member"></typeAlias>
</typeAliases>
</configuration>
resources 폴더 - mapper 폴더 - memberMapper.xml
<?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="Member">
<insert id="save" parameterType="member">
insert into member_table(memberEmail, memberPassword, memberName, memberAge, memberMobile)
values (#{memberEmail}, #{memberPassword}, #{memberName}, #{memberAge}, #{memberMobile})
</insert>
</mapper>
마이바티스 사용 회원가입 처리를 위한 쿼리문
namespace 이름 Member 와 sql.insert("Member.save",memberDTO) 호출하면서
id 는 Member.save 의 save를 호출한다.
즉 namespace = Member , id = save 이다.
parameterType 은 com.codingrecipe.member.dto.MemberDTO 풀경로를 적는데,
번거롭고 길기 때문에 약간의 줄임 형태로 member로 줄이려면
mybatis-config.xml 에서 알리아스 설정에 별칭을 지정하는 설정을 해줘서
alias로 적용한 member 로 사용이 가능하다.
네이티브 쿼리를 사용하며 테이블 이름 각 컬럼 값을 쓰게 된다.
각 위치의 데이터베이스 필드이름 과 클래스 필드명을 #{필드명} 로 표현해준다.
-로그인 기능
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
</head>
<body>
<form action="/member/login" method="post">
<input type="text" name="memberEmail" placeholder="이메일">
<input type="text" name="memberPassword" placeholder="비밀번호">
<input type="submit" value="로그인">
</form>
</body>
</html>
로그인은 이메일 , 비밀번호를 적어서 일치하면 main
틀렸으면 로그인 페이지가 다시 나오게 끔 한다.
MemberController - login메소드 로그인 처리를 하는 메서드
@PostMapping("/login")
public String login(@ModelAttribute MemberDTO memberDTO,
HttpSession session) {
boolean loginResult = memberService.login(memberDTO);
if (loginResult) {
session.setAttribute("loginEmail", memberDTO.getMemberEmail());
return "main";
} else {
return "login";
}
}
로그인을 하게 되면 Session 활용
매개변수에 HttpSession 줘서 로그인을 성공하게 되면 setAttribute 로 저장 한다.
세션에다가 로그인한 계정 정보를 입력을 하도록 한다.
그다음 main.jsp 로 넘어가고
실패시 login 페이지로 간다
MemberService
public boolean login(MemberDTO memberDTO) {
MemberDTO loginMember = memberRepository.login(memberDTO);
if (loginMember != null) {
return true;
} else {
return false;
}
}
login 한 결과를 DTO로 받아온다
그 결과에 null 여부에 따라 true (로그인 성공) , false (결과 없음) 리턴
Repository
public MemberDTO login(MemberDTO memberDTO) {
return sql.selectOne("Member.login", memberDTO);
}
sql.selectOne은 selectOne은 조회결과가 하나 일때
MemberDTO는 로그인한 부분을 호출 DTO객체를 넘겨준다.
조회결과가 여러개면 ? 500에러 발생
<select id="login" parameterType="member" resultType="member">
select * from member_table where memberEmail=#{memberEmail} and memberPassword=#{memberPassword}
</select>
member에 대한 정보를 줘서 쿼리문 이메일 과 패스워드를 조회 한 결과값을 member로 반환 한다.
넘겨받은 이메일과 패스워드를 둘다 만족하는 결과가 있는지 select 한다
사용자가 회원가입 할때 이메일과 비번이 둘다 일치하는지
select 할때는 resultType 이 있어야 한다.
Main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>main</title>
</head>
<body>
<h2>${sessionScope.loginEmail} 님 환영합니다.</h2>
<button onclick="update()">내정보 수정하기</button>
<button onclick="logout()">로그아웃</button>
</body>
<script>
const update = () => {
location.href = "/member/update";
}
const logout = () => {
location.href = "/member/logout";
}
</script>
</html>
세션에 담긴 이메일 띄어주고
수정을 위한 버튼 로그인을 위한 버튼을 만들어 놨다
-- 회원 목록 조회 기능
@GetMapping("/")
public String findAll(Model model) {
List<MemberDTO> memberDTOList = memberService.findAll();
model.addAttribute("memberList", memberDTOList);
return "list";
}
데이터를 가져가야 하는 Model 객체 필요
memberService 클래스
public List<MemberDTO> findAll() {
return memberRepository.findAll();
}
memberRepository 클래스
public List<MemberDTO> findAll() {
return sql.selectList("Member.findAll");
}
sql.selectList 값이 여러개인 경우
memberMapper.xml
<select id="findAll" resultType="member">
select * from member_table
</select>
전달받은 값이 없으므로 ParameterType은 없고
결과값인 ResultType 이 필요
-> MySql에서 실행해보고 마이바티스에 적용하는게 좋다 쿼리문 문제되는 경우 500에러가 발생 한다.
list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>list</title>
</head>
<body>
<table>
<tr>
<th>id</th>
<th>email</th>
<th>password</th>
<th>name</th>
<th>age</th>
<th>mobile</th>
<th>조회</th>
<th>삭제</th>
</tr>
<c:forEach items="${memberList}" var="member">
<tr>
<td>${member.id}</td>
<td>
<a href="/member?id=${member.id}">${member.memberEmail}</a>
</td>
<td>${member.memberPassword}</td>
<td>${member.memberName}</td>
<td>${member.memberAge}</td>
<td>${member.memberMobile}</td>
<td>
<a href="/member?id=${member.id}">조회</a>
</td>
<td>
<button onclick="deleteMember('${member.id}')">삭제</button>
</td>
</tr>
</c:forEach>
</table>
</body>
<script>
const deleteMember = (id) => {
console.log(id);
location.href = "/member/delete?id="+id;
}
</script>
</html>
JSTL 의 반복문을 사용하기 위해
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 선언해준다.
이제 조회 시 아이디 값을 해당하는 정보를 가지고 화면에 보여주기
// /member?id=1
@GetMapping
public String findById(@RequestParam("id") Long id, Model model) {
MemberDTO memberDTO = memberService.findById(id);
model.addAttribute("member", memberDTO);
return "detail";
}
Service 클래스
public MemberDTO findById(Long id) {
return memberRepository.findById(id);
}
나중에 잘못된 아이디 요청이 올수도 있으니 해당 아이디 일치하는 화면이 없다 라듯이
기능을 보강할때 고민해보면 좋을것 같다.
Repository 클래스
public MemberDTO findById(Long id) {
return sql.selectOne("Member.findById", id);
}
Membermapper.xml
<select id="findById" parameterType="Long" resultType="member">
select * from member_table where id=#{id}
</select>
ParameterType : id - Long 타입
ResultType : member
detail.jsp - 회원 정보를 뿌려 준다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>detail</title>
</head>
<body>
<table>
<tr>
<th>id</th>
<td>${member.id}</td>
</tr>
<tr>
<th>email</th>
<td>${member.memberEmail}</td>
</tr>
<tr>
<th>password</th>
<td>${member.memberPassword}</td>
</tr>
<tr>
<th>name</th>
<td>${member.memberName}</td>
</tr>
<tr>
<th>age</th>
<td>${member.memberAge}</td>
</tr>
<tr>
<th>mobile</th>
<td>${member.memberMobile}</td>
</tr>
</table>
</body>
</html>
Controller 에서 아이디 정보를 가져와서 조회된 결과값을 JSP 에 뿌려준다
- 삭제 기능
<button onclick="deleteMember('${member.id}')">삭제</button>
삭제 버튼 클릭 시 전달하는 값을 싱글쿼터로 묶는게 중요하다.
<script>
const deleteMember = (id) => {
console.log(id);
location.href = "/member/delete?id="+id;
}
</script>
id값이 넘어와서 주소값으로 넘기게 된다.
@GetMapping("/delete")
public String delete(@RequestParam("id") Long id) {
memberService.delete(id);
return "redirect:/member/";
}
Controller
@GetMapping("/delete")
public String delete(@RequestParam("id") Long id) {
memberService.delete(id);
return "redirect:/member/";
}
삭제 처리를 수행하고 그 다음 리스트를 재요청 하는 형식
redirect 방식 재 요청
Service 클래스
public void delete(Long id) {
memberRepository.delete(id);
}
Repository 클래스
public void delete(Long id) {
sql.delete("Member.delete", id);
}
mapper.xml
<delete id="delete" parameterType="Long">
delete from member_table where id=#{id}
</delete>
쿼리문 작성해 준다.
delete 는 int 타입으로 반환해서 삭제가 되면 1 삭제가 안되면 0 으로 반환한다.
삭제가 됬냐 안됐냐 판단이 가능하다.
-- 수정 기능 (2번의 요청이 발생한다)
1. 수정을 요청하면 수정 요청 해서 수정을 위한 화면을 띄어준다.
2. 수정 화면에서 전화번호 와 나이 값을 수정을 하게 한다.
3. 값을 db에 반영 시킨다.
4. 수정이 끝나면 회원의 상세 화면을 띄어준다.
<body>
<h2>${sessionScope.loginEmail} 님 환영합니다.</h2>
<button onclick="update()">내정보 수정하기</button>
<button onclick="logout()">로그아웃</button>
</body>
<script>
const update = () => {
location.href = "/member/update";
}
const logout = () => {
location.href = "/member/logout";
}
</script>
수정을 위한 페이지를 띄어 준다.
// 수정화면 요청
@GetMapping("/update")
public String updateForm(HttpSession session, Model model) {
// 세션에 저장된 나의 이메일 가져오기
String loginEmail = (String) session.getAttribute("loginEmail");
MemberDTO memberDTO = memberService.findByMemberEmail(loginEmail);
model.addAttribute("member", memberDTO);
return "update";
}
주소를 요청해서 왔는데, 누구의 정보를 수정할것인지 알아야 되므로
HttpSession 에다가 내 로그인 정보를 담겨있으므로 이것을 활용해본다
(String) session.getAttribute("loginEmail") Object를 String으로 형변환 해서 가져온다.
memberService 클래스
public MemberDTO findByMemberEmail(String loginEmail) {
return memberRepository.findByMemberEmail(loginEmail);
}
이메일을 조회 한다.
Repository 클래스
public MemberDTO findByMemberEmail(String loginEmail) {
return sql.selectOne("Member.findByMemberEmail", loginEmail);
}
Membermapper.xml
<select id="findByMemberEmail" parameterType="String" resultType="member">
select * from member_table where memberEmail=#{loginEmail}
</select>
Controller 에서 조회된 결과를 update.jsp로 넘긴다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>update</title>
</head>
<body>
<form action="/member/update" method="post" name="updateForm">
id: <input type="text" name="id" value="${member.id}"readonly>
email: <input type="text" name="memberEmail" value="${member.memberEmail}"readonly>
password: <input type="text" name="memberPassword" id="memberPassword">
name: <input type="text" name="memberName" value="${member.memberName}" readonly>
age: <input type="text" name="memberAge" value="${member.memberAge}">
mobile: <input type="text" name="memberMobile" value="${member.memberMobile}">
<input type="button" value="수정" onclick="update()">
</form>
</div>
</body>
<script>
const update = () => {
const passwordDB = '${member.memberPassword}';
const password = document.getElementById("memberPassword").value;
if (passwordDB == password) {
document.updateForm.submit();
} else {
alert("비밀번호가 일치하지 않습니다!");
}
}
</script>
</html>
readonly 읽기 전용 으로 수정할수 없는 부분은 readonly 으로 설정해 준다.
값은 value 라는 속성으로 controller 에서 member라는 이름으로 member라는 파라미터로 각각의 필드를 찍어주고있다
input type 이 submit 이 아니라 button
submit 으로 하면 form 태그가 제출되는데
button은 다른 기능을 주고 싶을때 사용한다.
form 태그 안에서 button을 줘서 함수를 호출 한다. - > onclick = "update()" 호출
<script>
const update = () => {
const passwordDB = '${member.memberPassword}';
const password = document.getElementById("memberPassword").value;
if (passwordDB == password) {
document.updateForm.submit();
} else {
alert("비밀번호가 일치하지 않습니다!");
}
}
</script>
DB에 저장된 비밀번호 랑 사용자가 입력한 비밀번호를 비교 한다.
사용자가 입력한 비밀번호를 DOM API 를 이용해서 getElementById로 가져온다
일치하면 document.updateForm.submit() Form 태그를 제어한다.
-- 수정 처리 (PostMapping)
// 수정 처리
@PostMapping("/update")
public String update(@ModelAttribute MemberDTO memberDTO) {
boolean result = memberService.update(memberDTO);
if (result) {
return "redirect:/member?id=" + memberDTO.getId();
} else {
return "index";
}
}
수정이 끝나면 회원의 상세페이지로 이동시킨다.
수정 실패시 index.jsp로 이동
memberSerivce
public boolean update(MemberDTO memberDTO) {
int result = memberRepository.update(memberDTO);
if (result > 0) {
return true;
} else {
return false;
}
}
update 결과 값 수정이 완료되면 1 , 실패시 0 반환
Repository
public int update(MemberDTO memberDTO) {
return sql.update("Member.update", memberDTO);
}
mapper.xml
<update id="update" parameterType="member">
update member_table set memberAge=#{memberAge}, memberMobile=#{memberMobile}
where id=#{id}
</update>
여러개의 컬럼값을 수정할때는 and (x) , 콤마를 준다
수정 처리 과정은 2번의 과정이 필요하다.
이메일 중복 체크 - Ajax 사용 프론트에서 리액트 등을 사용 할 수 있다.
같이 사용이 가능한 문법 이다.
DB에 동일한 주소가 있는지 체크
save.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>save</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<form action="/member/save" method="post">
<input type="text" name="memberEmail" placeholder="이메일" id="memberEmail" onblur="emailCheck()">
<p id="check-result"></p>
<input type="text" name="memberPassword" placeholder="비밀번호">
<input type="text" name="memberName" placeholder="이름">
<input type="text" name="memberAge" placeholder="나이">
<input type="text" name="memberMobile" placeholder="전화번호">
<input type="submit" value="회원가입">
</form>
</body>
onblur : 이벤트 처리하는 방법 , 입력창을 벗어났을때 이 함수를 호출하는 이벤트 처리 방식
<script>
// 이메일 입력값을 가져오고,
// 입력값을 서버로 전송하고 똑같은 이메일이 있는지 체크한 후
// 사용 가능 여부를 이메일 입력창 아래에 표시
const emailCheck = () => {
const email = document.getElementById("memberEmail").value;
const checkResult = document.getElementById("check-result");
console.log("입력한 이메일", email);
$.ajax({
// 요청방식: post, url: "email-check", 데이터: 이메일
type: "post",
url: "/member/email-check",
data: {
"memberEmail": email
},
success: function(res) {
console.log("요청성공", res);
if (res == "ok") {
console.log("사용가능한 이메일");
checkResult.style.color = "green";
checkResult.innerHTML = "사용가능한 이메일";
} else {
console.log("이미 사용중인 이메일");
checkResult.style.color = "red";
checkResult.innerHTML = "이미 사용중인 이메일";
}
},
error: function(err) {
console.log("에러발생", err);
}
});
}
</script>
ajax 는 화면이 바뀌는게 없이 서버와 HTTP 요청을 주고받을때
비동기 통신을 사용하는데
get 또는 post 요청 방식이 필요하고 post 방식으로 url 주소로 보내주고
보내주고 하는 내용은 data : { 파라미터이름 : 담기는 값 } - 사용자가 입력한 이메일 값이 된다.
success : 요청이 성공하면 응답이 오게 되고 응답에 대해서 처리 한다.
function(res)
res 에 ok 값이 담겨오면 db에 없는 이메일이다 - 사용 가능
error : function(err) 응답이 제대로 오지 않는 경우
@PostMapping("/email-check")
public @ResponseBody String emailCheck(@RequestParam("memberEmail") String memberEmail) {
System.out.println("memberEmail = " + memberEmail);
String checkResult = memberService.emailCheck(memberEmail);
return checkResult;
}
post 방식으로 요청을 보내면 postMapping 으로 받는다
Ajax나 응답을 처리할때 ResponseBody 로 응답을 받는다
String 타입으로 받는데 @ResponseBody 로 꼭 받는다.
MemberService
public String emailCheck(String memberEmail) {
MemberDTO memberDTO = memberRepository.findByMemberEmail(memberEmail);
if (memberDTO == null) {
return "ok";
} else {
return "no";
}
}
res값으로 결과에 대한 응답값을 리턴받는다.
조회결과가 있으면 그 이메일을 사용하는 사용자가 있다.
없으면 그 이메일을 사용하는 사용자가 없다
Repository
public MemberDTO findByMemberEmail(String loginEmail) {
return sql.selectOne("Member.findByMemberEmail", loginEmail);
}
membermapper.xml
<select id="findByMemberEmail" parameterType="String" resultType="member">
select * from member_table where memberEmail=#{loginEmail}
</select>
500 에러 발생시 -> 매퍼에서 문제가 발생할 확률이 높다
'BACKEND > 스프링 Spring' 카테고리의 다른 글
spring 게시판 인텔리제이로 게시판 글조회, 조회수 , 글삭제 , 글수정 (2) | 2024.01.04 |
---|---|
인텔리제이 smart Tomcat 설치 (0) | 2024.01.03 |
스프링 MVC GIS 데이터를 처리 RESTful API 사용 (0) | 2023.12.21 |
Spring MVC 스프링 세션 로그인, 로그아웃 (0) | 2023.12.19 |
Spring Handler Interceptor (0) | 2023.12.19 |