스프링 MVC ( 요청 매핑, 커맨드 객체, 리다이렉트, 폼 태그, 모델 ) 

약관 동의, 회원 가입, 로그인 후 계정 이름 표시 

 

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>sp5</groupId>
	<artifactId>sp5-chap11Practice</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<dependencies>
		<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>javax.servlet.jsp-api</artifactId>
			<version>2.3.2-b02</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jdbc</artifactId>
			<version>8.5.27</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.25</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.7.0</version>
				<configuration>
					<source>11</source>
					<target>11</target>
					<encoding>utf-8</encoding>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.2.2</version>
			</plugin>
		</plugins>
	</build>

</project>

 

 

어제 사용한 spring패키지 내용물 그대로 사용 ( DTO, DAO, Service, 익셉션, Request )

GitHub 60day 확인 https://github.com/cojuns/choongang/tree/master/60day/%EC%95%BD%EA%B4%80%EB%8F%99%EC%9D%98_%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85_(%20''%EB%8B%98%20%EA%B0%80%EC%9E%85%20%EC%B6%95%ED%95%98%20)/spring 

 

 

Datasource, 트랜잭션매니져 스프링 설정 클래스 작성 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberRegisterService;

@Configuration
@EnableTransactionManagement
public class MemberConfig {

	@Bean(destroyMethod = "close")
	public DataSource dataSource() {
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8");
		ds.setUsername("spring5");
		ds.setPassword("spring5");
		ds.setInitialSize(2);
		ds.setMaxActive(10);
		ds.setTestWhileIdle(true);
		ds.setMinEvictableIdleTimeMillis(60000 * 3);
		ds.setTimeBetweenEvictionRunsMillis(10 * 1000);
		return ds;
	}

	@Bean
	public PlatformTransactionManager transactionManager() {
		DataSourceTransactionManager tm = new DataSourceTransactionManager();
		tm.setDataSource(dataSource());
		return tm;
	}

	@Bean
	public MemberDao memberDao() {
		return new MemberDao(dataSource());
	}

	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService(memberDao());
	}

	@Bean
	public ChangePasswordService changePwdSvc() {
		ChangePasswordService pwdSvc = new ChangePasswordService();
		pwdSvc.setMemberDao(memberDao());
		return pwdSvc;
	}
}

 

 

스프링 MVC 기본 설정 파일 

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

	@Override
	public void configureDefaultServletHandling(
			DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
	}



}

 

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1" metadata-complete="true">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				config.MemberConfig
				config.MvcConfig
				config.ControllerConfig
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</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>

 

 

컨트롤러 매핑 애노테이션 설정 ( 주석을 보면 / "/register/step2" 방식은 3가지로 적용 가능 )

package controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import spring.DuplicateMemberException;
import spring.MemberRegisterService;
import spring.RegisterRequest;

@Controller
public class RegisterController {
	
	@Autowired
	private MemberRegisterService memberRegisterService;
	
	@GetMapping("/register/step1")
	public String handleStep1() {
		return "register/step1";
	}
	
	// 1번째 방법 HttpServletRequest 방식
//	@PostMapping("register/step2")
//	public String handleStep2(HttpServletRequest request) {
//		String agreepParam = request.getParameter("agree");
//		System.out.println(agreepParam);
//		if(agreepParam == null || !agreepParam.equals("true")) {
//			return "register/step1";
//		}
//		return "register/step2";
//	}
	
	// 2번째 방법 @RequestParam 방식 ( 해당 방식 많이 이용 ) 
	@PostMapping("/register/step2")
	public String handleStep2(@RequestParam(value = "agree",// name 속성 안써도 됨 
											defaultValue = "false") Boolean agree) {
		
		System.out.println(agree);
		if(!agree) {
			return "register/step1";
		}
		return "register/step2";
	}
	
	// 3번째 방법 required = true 
//	@PostMapping("/register/step2")
//	public String handleStep2(@RequestParam(required = true,defaultValue = "false" 
//											) Boolean agree) {
//		
//		System.out.println(agree);
//		if(!agree) {
//			return "register/step1";
//		}
//		return "register/step2";
//	}
	
	
	@GetMapping("/register/step2")
	public String handleStep2Get() {
		return "redirect:/register/ster1";
	}
	
	@PostMapping("/register/step3")
	public String handleStep3(RegisterRequest registerRequest) {
		try {
			memberRegisterService.regist(registerRequest);
			return "register/step3";
		}catch(DuplicateMemberException e) {
			return "register/step2";
		}
		
		
		
	}
}

 

 

ControllerConfig.java 파일에 @Autowired, @Bean 설정 

package config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import controller.RegisterController;
import spring.MemberRegisterService;

@Configuration
public class ControllerConfig {

	@Autowired
	private MemberRegisterService memberRegSvc;
	
	@Bean
	public RegisterController registerController() {
		return new RegisterController();
	}
	
}

 

 

JSP 파일 설정

index.jsp ( 서버 실행 시 켜지는 jsp )

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <title>메인</title>
</head>
<body>
    <p>환영합니다.</p>
    <p><a href="<c:url value="/register/step1" />">[회원 가입하기]</a>
</body>
</html>

 

step1.jsp ( 약관 동의 체크 ) 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
</head>
<body>
<h2>약관</h2>
<p>약관 내용</p>
<form action="step2" method="post">
<label>
<input type="checkbox" name="agree" value="true">약관 동의
</label>
<input type="submit" value="다음 단계" />
</form>
</body>
</html>

 

step2.jsp ( 회원가입 ) 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
</head>
<body>
<h2>회원 정보 입력</h2>
<form action="step3" method="post">
<p>
<label>이메일:<br>
<input type="text" name="email" id="email">
</label>
</p>
<p>
<label>이름:<br>
<input type="text" name="name" id="name">
</label>
</p>
<p>
<label>비밀번호:<br>
<input type="password" name="password" id="password">
</label>
</p>
<p>
<label>비밀번호 확인:<br>
<input type="password" name="confirmPassword" id="confirmPassword">
</label>
</p>
<input type="submit" value="가입완료">
</form>
</body>
</html>

 

step3.jsp ( 회원가입 완료 후 ID 표시 ) name 값 바꿔서 다른 거 출력 가능

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
</head>
<body>
	<p><strong>${registerRequest.name}님</strong></p>
	<p><a href="<c:url value='/main'/>">[첫 화면 이동]</a></p>
</body>
</html>

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-16 62일차  (0) 2023.08.16
2023-08-11 61일차  (0) 2023.08.11
2023-08-09 59일차  (0) 2023.08.09
2023-08-08 58일차  (0) 2023.08.08
2023-08-07 57일차  (0) 2023.08.07

스프링 MVC

 

입력한 단수 구구단 출력 ( Maven, SpringMVC, 다이나믹웹프로젝트 ) 

 

1. 다이나믹웹프로젝트 생성 

 

2. Maven 설정

 

 

3. pom.xml => dependencies 설정  => Maven 업데이트

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>_testSpringMVC0809</groupId>
  <artifactId>_testSpringMVC0809</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
    <dependencies>
		<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>javax.servlet.jsp-api</artifactId>
			<version>2.3.2-b02</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
	</dependencies>
  
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>11</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
      </plugin>
    </plugins>
  </build>
</project>

 

 

4.web.xml에서 contextConfigLocation => dispatcher => encodingFilter 설정 

( WEB-INF ) 

<?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_4_0.xsd" version="4.0">
  <display-name>_springMVC0808</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				config.MvcConfig
				config.ControllerConfig
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</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>

 

 

5. config 패키지 스프링 MVC 설정 ( @Configuration 둘 다 설정) 

 1). @EnableWebMvc ( WebMvcConfigurer 디폴트이기 때문에 자동 구현X 직접 구현해야 됨 (Source) ) 

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
		
	}

}

 

 2). 컨트롤러 @Bean 등록

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import chap10.MyController;

@Configuration
public class ControllerConfig {
	
	@Bean
	public MyController myController() {
		return new MyController();
		
	}
}

 

 

 

5. 컨트롤러(Controller) 설정

@Getmapping ( 입력 jsp에 보통 설정 ) @PostMapping ( url에 값을 숨길 수 있기 때문에 처리 부분에 사용 ) 

package chap10;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {
	

	
	@GetMapping("/gugu")
	public String add() {
		
		return "gugudanform";
	}
	
	@PostMapping("/gugu") // post 맵핑 
	public String result(Model model, @RequestParam String dan) {
		List<String> list = new ArrayList<>();
		int num = Integer.parseInt(dan);
		for(int i=1; i <=9; i++) {

			String res = String.format("%d X %d = %d", i, num, i*num);
			list.add(res);
		}

		
		model.addAttribute("list", list);
		return "result";
	}
	

			
	
}

 

 

6. JSP 설정 ( WEB-INF => view폴더 ) 

jstl 사용 ( import 부분 확인 )

 

form.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<form action="<c:url value='/gugu'/>" method = "post">
단 입력 : <input type="text" name="dan" />
<input type="submit"/>

</body>
</html>

 

result.jsp ( 컨트롤러에서 list 값을 가져와서 var="gugu"에 주입 ( 목록을 출력해야되기 때문에 jstl에 forEach 사용

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<!-- gugu 내부 변수 -->
	<c:forEach var="gugu" items="${list}">
	${gugu} <br/> 
	</c:forEach>
	

</body>
</html>

 

 

7. 결과

 

 

 

 

 

 

 

로그인, 로그아웃, 회원가입,  ( Maven, SpringMVC, 다이나믹웹프로젝트 ) 

해당 클래스다이어그램 구조로 구현, 스프링MVC 4번까지 동일

 

 

HandlerURI 설정

/join.do=member.command.JoinHandler
/login.do=auth.command.LoginHandler
/logout.do=auth.command.LogoutHandler
/changePwd.do=member.command.ChangePasswordHandler
/article/write.do=article.command.WriteArticleHandler
/article/list.do=article.command.ListArticleHandler
/article/read.do=article.command.ReadArticleHandler
/article/modify.do=article.command.ModifyArticleHandler

 

스프링 설정 ( DataSourece 사용해서 DB접속과 트랜잭션 매니져 설정 ) 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import auth.service.LoginService;
import cotroller.LogController;
import cotroller.MyController;
import member.dao.MemberDao;
import member.service.ChangePasswordService;
import member.service.JoinService;

@Configuration
@EnableTransactionManagement
public class ControllerConfig {
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/board?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("jspexam");
		ds.setPassword("jsppw");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MemberDao memberDao() {
		return new MemberDao(dataSource());
	}
	
	
	@Bean
	public LoginService loginservice() {
		return new LoginService();
	}
	
	@Bean
	public ChangePasswordService changePasswordService() {
		
		return new ChangePasswordService();
	}
	
	@Bean
	public PlatformTransactionManager transactionManager() {
		DataSourceTransactionManager tm = new DataSourceTransactionManager();
		tm.setDataSource(dataSource());
		return tm;
	}
	
	@Bean
	public LogController logController() {
		return new LogController();
	}
	
	@Bean
	public JoinService joinService() {
		return new JoinService();
	}
	
}

 

DAO 설정

package member.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

import member.model.Member;

public class MemberDao {
	
	private JdbcTemplate jdbcTemplate;
	
	public MemberDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	private Date toDate(Timestamp date) {
		return date == null ? null : new Date(date.getTime());
	}
	
	private Member makeMemberFromResultSet(ResultSet rs) throws SQLException {
		Member member = new Member();
		member.setId(rs.getString("memberid"));
		member.setName(rs.getString("name"));
		member.setPassword(rs.getString("password"));
		member.setRegDate(rs.getDate("regdate"));
		
		return member;

	}
	
	public List<Member> selectList(){
		String sql = "select * from member";
		
		List<Member> list = jdbcTemplate.query(sql, (ResultSet rs, int rowNum) -> {
			return makeMemberFromResultSet(rs);
		});
		return list;
	}
	
	
	public int selectCount() {
		String sql = "select count(*) from member";
		Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
		return count;
	}
	
	
//	public void insert(Connection conn, Member mem) throws SQLException {
//		try (PreparedStatement pstmt = 
//				conn.prepareStatement("insert into member values(?,?,?,?)")) {
//			pstmt.setString(1, mem.getId());
//			pstmt.setString(2, mem.getName());
//			pstmt.setString(3, mem.getPassword());
//			pstmt.setTimestamp(4, new Timestamp(mem.getRegDate().getTime()));
//			pstmt.executeUpdate();
//		}
//	}
	
	public void insert1(Member member) {
		String sql = "insert into member (memberid, name, password, regdate)"
				+ "values (?,?,?,now())";
		jdbcTemplate.update(sql,
				member.getId(),
				member.getName(),
				member.getPassword()
				);
	}
	
	public int delete(String memberid) {
		String sql = "delete from member where memberid = ?";
		return jdbcTemplate.update(sql,
				new Object[] {memberid});
	}
	
//	public void update(Connection conn, Member member) throws SQLException {
//		try (PreparedStatement pstmt = conn.prepareStatement(
//				"update member set name = ?, password = ? where memberid = ?")) {
//			pstmt.setString(1, member.getName());
//			pstmt.setString(2, member.getPassword());
//			pstmt.setString(3, member.getId());
//			pstmt.executeUpdate();
//		}
//	}
	
	public void updatePassword(Member member) {
		String sql = "update member set name=?, password=?, regdate=? where memberid =?";
		jdbcTemplate.update(sql,
				member.getName(),
				member.getPassword(),
				member.getRegDate(),
				member.getId()
				);
	}
	
//	public Member selectById(Connection conn, String id) throws SQLException {
//		PreparedStatement pstmt = null;
//		ResultSet rs = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"select * from member where memberid = ?");
//			pstmt.setString(1, id);
//			rs = pstmt.executeQuery();
//			Member member = null;
//			if (rs.next()) {
//				member = new Member(
//						rs.getString("memberid"), 
//						rs.getString("name"), 
//						rs.getString("password"),
//						toDate(rs.getTimestamp("regdate")));
//			}
//			return member;
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(pstmt);
//		}
//	}
	
//	public Member selectById(String memberid) {
//		String sql = "select * from member where memberid = ?";
//		return jdbcTemplate.queryForObject(sql, 
//				(ResultSet rs, int rowNum) -> {
//					return makeMemberFromResultSet(rs);
//				}, memberid);
//		
//	}
	
	public Member selectById(String id) {
		String sql = "select * from member where memberid = ?";
		List<Member> list = this.jdbcTemplate.query(sql, (rs, r)->{
			Member member = new Member(
					rs.getString("memberid"), 
					rs.getString("name"), 
					rs.getString("password"),
					toDate(rs.getTimestamp("regdate")));
			return member;
		}, id);
		return list.isEmpty() ? null : list.get(0);
	}
	
	

	
	







}

 

서비스 설정 ( DAO @Autowired 설정, 메서드 @Transactional 설정 ) 

 

LoginService 로그인 

package auth.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import member.dao.MemberDao;
import member.model.Member;

public class LoginService {
	
	@Autowired
	private MemberDao memberDao; 
	
	@Transactional
	public User login(String id, String password) {
		
			Member member = memberDao.selectById(id);
			if (member == null) {
				throw new LoginFailException();
			}
			if (!member.matchPassword(password)) {
				throw new LoginFailException();
			}
			return new User(member.getId(), member.getName());
		} 
	}

 

ChangePasswordService 패스워드 변경

package member.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import member.dao.MemberDao;
import member.model.Member;

public class ChangePasswordService {
	
	@Autowired
	private MemberDao memberDao;
	
	@Transactional
	public void changePassword(String userId, String curPwd, String newPwd) {
			
			Member member = memberDao.selectById(userId);
			if (member == null) {
				throw new MemberNotFoundException();
			}
			if (!member.matchPassword(curPwd)) {
				throw new InvalidPasswordException();
			}
			member.changePassword(newPwd);
			memberDao.updatePassword(member);

		} 
	}

 

JoinService 회원가입

package member.service;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import member.dao.MemberDao;
import member.model.Member;

public class JoinService {
	
	@Autowired
	private MemberDao memberDao;
	
	@Transactional
	public void join(JoinRequest joinReq) {

			Member member = memberDao.selectById(joinReq.getId());
			if (member != null) {
				throw new DuplicateIdException();
			}
			
			memberDao.insert1( 
					new Member(
							joinReq.getId(), 
							joinReq.getName(), 
							joinReq.getPassword(), 
							new Date())
					);
			
		} 
	}

 

 

 

컨트롤러 설정

package cotroller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import auth.service.LoginFailException;
import auth.service.LoginService;
import auth.service.User;
import member.service.ChangePasswordService;
import member.service.DuplicateIdException;
import member.service.InvalidPasswordException;
import member.service.JoinRequest;
import member.service.JoinService;
import member.service.MemberNotFoundException;

///join.do=member.command.JoinHandler
///login.do=auth.command.LoginHandler
///logout.do=auth.command.LogoutHandler
///changePwd.do=member.command.ChangePasswordHandler

@Controller
public class LogController {
	
	@Autowired
	private LoginService loginService;
	
	@Autowired
	private ChangePasswordService changePwdSvc;
	
	@Autowired
	private JoinService joinService;
	
	@GetMapping("/login.do")
	public String login1() {
		
		return "loginForm";
	}
	
	@PostMapping("/login.do")
	public String login2(Model model, @RequestParam String id, 
										@RequestParam String password,
										HttpServletRequest request) {
										// HttpServletRequest request 세션 정보 가져오기

		Map<String, Boolean> errors = new HashMap<>();
		model.addAttribute("errors", errors); // 빈 칸일 때 에러 메시지 표시

		if (id == null || id.isEmpty())
			errors.put("id", Boolean.TRUE);
		if (password == null || password.isEmpty())
			errors.put("password", Boolean.TRUE);

		if (!errors.isEmpty()) {
			return "loginForm";
		}
		
		// 세션 정보 가져오기
		try {
			User user = loginService.login(id, password);
			request.getSession().setAttribute("authUser", user);
			return "redirect:/index.jsp";
		} catch (LoginFailException e) {
			errors.put("idOrPwNotMatch", Boolean.TRUE);
			return "loginForm";
		}
		
		
	}
	
	@GetMapping("/logout.do")
	public String logout(HttpServletRequest req) {
		HttpSession session = req.getSession(false);
		if (session != null) {
			session.invalidate();
		}
		return "redirect:/index.jsp";
	}
	
	
	@GetMapping("/changePwd.do")
	public String changePw1() {
		return "changePwdForm";
	}
	
	@PostMapping("/changePwd.do")
	public String changePw2(Model model,
							@RequestParam String curPwd,
							@RequestParam String newPwd,
							HttpServletRequest req,
							HttpServletResponse res) {
		
		User user = (User)req.getSession().getAttribute("authUser");
		
		Map<String, Boolean> errors = new HashMap<>();
		model.addAttribute("errors", errors);

		
		if (curPwd == null || curPwd.isEmpty()) {
			errors.put("curPwd", Boolean.TRUE);
		}
		if (curPwd == null || curPwd.isEmpty()) {
			errors.put("newPwd", Boolean.TRUE);
		}
		if (!errors.isEmpty()) {
			return "changePwdForm";
		}
		
		try {
			changePwdSvc.changePassword(user.getId(), curPwd, newPwd);
			return "changePwdSuccess";
		} catch (InvalidPasswordException e) {
			errors.put("badCurPwd", Boolean.TRUE);
			return "changePwdForm";
		} catch (MemberNotFoundException e) {
			
			try {
				res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			}catch (IOException e1) {
				e1.printStackTrace();
			}
			return null;
		}
		
		
	}
	
	@GetMapping("/join.do")
	public String join1() {
		
		
		return "joinForm";
	}
	
	@PostMapping("/join.do")
	public String join2(HttpServletRequest req, Model model) {
		JoinRequest joinReq = new JoinRequest();
		joinReq.setId(req.getParameter("id"));
		joinReq.setName(req.getParameter("name"));
		joinReq.setPassword(req.getParameter("password"));
		joinReq.setConfirmPassword(req.getParameter("confirmPassword"));
		
		
		
		Map<String, Boolean> errors = new HashMap<>();
		model.addAttribute("errors", errors);
		
		joinReq.validate(errors);
		
		if (!errors.isEmpty()) {
			return "joinForm";
		}
		
		try {
			joinService.join(joinReq);
			return "joinSuccess";
		} catch (DuplicateIdException e) {
			errors.put("duplicateId", Boolean.TRUE);
			return "joinForm";
		}
		
		
	}
	
}

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-11 61일차  (0) 2023.08.11
2023-08-10 60일차  (0) 2023.08.10
2023-08-08 58일차  (0) 2023.08.08
2023-08-07 57일차  (0) 2023.08.07
2023-08-04 56일차  (0) 2023.08.04

스프링 MVC

 

스프링 MVC 설정

 

<packaging>war</packaging>

이 태그의 기본값은 jar로서 서블릿/JSP를 이용한 웹 어플리케이션을 개발할 경우 war를 값으로 주어야 한다.

war ( Web Application Archive )

 

pom.xml 

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>_springMVC0808</groupId>
  <artifactId>_springMVC0808</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
    <dependencies>
		<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>javax.servlet.jsp-api</artifactId>
			<version>2.3.2-b02</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
	</dependencies>
  
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>11</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
      </plugin>
    </plugins>
  </build>
</project>

 

 

구성요소 설정 ( @EnableWebMvc ) 

configureViewResolvers : JSP 이용해서 컨트롤러의 실행 결과를 보여주기 위한 설정 추가

Controller 설정 파일에서 return "hello"; 설정 시 hello.jsp로 이동

MvcConfig

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
		
	}

}

 

위에 코드에서 오버라이드는 밑에 이미지 처럼 설정 해주면 된다.

 

 

 

web.xml 파일에 DispatcherServlet 설정  ( WEB-INF 위치에 )

( 스프링 MVC가 웹 요청을 처리하려면 DispatcherServlet 설정 필요 ) 

<?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_4_0.xsd" version="4.0">
  <display-name>_springMVC0808</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				config.MvcConfig
				config.ControllerConfig
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</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>

 

web.xml파일에서 중요한 부분은 밑에 코드다.

contextConfiguration 초기화 파라미터의 값을 지정한다. 이 파라미터에는 스프링 설정 클래스 목록을 지정한다.

각 설정 파일의 경로는 줄바꿈이나 콤마로 구분 ( 해당 글에서는 MvcConfig 클래스만 작성 )

<init-param>
 <param-name>contextConfigLocation</param-name>
	<param-value>
		config.MvcConfig
		config.ControllerConfig
	</param-value>
</init-param>

 

 

 

컨트롤러 구현

@GetMapping : HTTP 요청 메서드 중 GET 메서드에 대한 매핑을 설정한다. 

Model 파라미터 : 컨트롤러의 처리 결과를 뷰에 전달할 때 사용

@RequestParam : HTTP 요청 파라미터의 값을 메서드의 파라미터로 전달할 때 사용 

 

"greeting" : 속성에 값을 설정 ( 변수 ),  값으로는 "안녕하세요.", 와 name 파라미터의 값을 연결한 문자열을 사용한다.JSP코드에서 이 속성을 이용해서 값을 출력한다.

 

return "hello" : 컨트롤러의 처리 결과를 보여줄 뷰 이름으로 "hello"를 사용한다. MvcConfig 파일에 밑에 코드 부분을 통해서 hello.jsp 파일로 이동 

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
		
	}

 

package chap09;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {
	
	@GetMapping("/hello") // URL 입력값
	public String aaa(Model model,
			@RequestParam(value = "name", required = false)String name) {
		model.addAttribute("greeting", "안녕하세요." + name);
		return "hello";// configureViewResolvers 붙여질 값 
	}
	
	@GetMapping("/add") 
	public String add(){
		
		return "addForm";
	}
	
	@GetMapping("/result") 
	public String result(Model model,
			@RequestParam(required = true, defaultValue = "0") Integer num1,
			@RequestParam(required = true, defaultValue = "0") Integer num2) {
		model.addAttribute("sum", num1 + num2 );
		return "result";
	}
	
}

 

 

 

 

스프링 빈으로 등록

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import chap09.HelloController;

@Configuration
public class ControllerConfig {
	
	@Bean
	public HelloController helloController() {
		return new HelloController();
		
	}
}

 

 

 

JSP 파일 생성 ( WEB-INF => view ) 

index 파일을 설정 안해놨기 때문에 프로젝트 Run As => ( http://localhost:9090/hello ) 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
인사말 : ${greeting}
</body>
</html>

합계 출력 해보기

 

addForm.jsp ( http://localhost:9090/add )

action 부분 그냥 /result로 할 시 jsp페이지 출력 불가 밑에 코드 처럼 하거나  Servers프로젝트 server.xml에 path="/"로 설정

<Context docBase="testddd" path="/testddd" reloadable="true" source="org.eclipse.jst.jee.server:testddd"/><Context docBase="_springMVC0808" path="/" reloadable="true" source="org.eclipse.jst.jee.server:_springMVC0808"/><Context docBase="_customTag0808" path="/_customTag0808" reloadable="true" source="org.eclipse.jst.jee.server:_customTag0808"/><Context docBase="_board" path="/board" reloadable="true" source="org.eclipse.jst.jee.server:_board"/></Host>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/result">
<input type="text" name="num1" />
<input type="text" name="num2" />
<input type="submit"/>
</form>
</body>
</html>

 

 

result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
합 = ${sum}
</body>
</html>

 

 

 

CustomTag ( 커스텀 태그 ) 

 

Date 오늘 날짜 출력 taglib 부분과 출력 부분 확인

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="tf" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<tf:now/>

</body>
</html>

컬러 지정, 출력 횟수 지정 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="tf" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<tf:toSpan color="red" iterNum="3">ㅎㅇ </tf:toSpan>
</body>
</html>

 

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-10 60일차  (0) 2023.08.10
2023-08-09 59일차  (0) 2023.08.09
2023-08-07 57일차  (0) 2023.08.07
2023-08-04 56일차  (0) 2023.08.04
2023-08-03 55일차  (0) 2023.08.03

스프링

 

트랜잭션 처리

두 개 이상의 쿼리를 한 작업으로 실행해야 할 때 사용하는 것이 트랜잭션이다.

트랜잭션은 여러 쿼리를 논리적으로 하나의 작업으로 묶어준다. 묶인 쿼리 중 하나라도 실패하면 전체 쿼리를 실패로

간주하고 실패 이전에 실행한쿼리를 취소한다. ( 롤백 ) 묶인 쿼리가 모두 성공 후 실제 반영하면 ( 커밋 )

 

@Transactional을 이용한 트랜잭션 처리 

해당 애노테이션을 사용하면 트랜잭션 범위를 쉽게 지정할 수 있다.

 

 예시 ) ChangPasswordService 메서드에 @Transactional애노테이션 설정

public class ChangePasswordService {
	
	@Autowired
	private MemberDao memberDao;
	@Transactional
	public void changePassword(String email, String oldPwd, String newPwd) {
		Member member = memberDao.selectByEmail(email);
		if (member == null)
			throw new MemberNotFoundException();

		member.changePassword(oldPwd, newPwd);

		memberDao.update(member);
	}

	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}

}

 

 

위에 설정으로 dao.selectByEmail()에서 실행하는 쿼리와 dto.changePassword()에서

실행하는 쿼리는 한 트랜잭션에 묶임 ( 밑에 코드 ) 

public class MemberDao {
	private JdbcTemplate jdbcTemplate;
	
	public MemberDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	public Member selectByEmail(String email) {
		String sql = "select * from MEMBER where EMAIL = ?";
		List<Member> result = jdbcTemplate.query(sql, new MemberRowMapper(), email);
		return result.isEmpty() ? null : result.get(0);
				
	}
	public void changePassword(String oldPassword, String newPassword) {
		if (!password.equals(oldPassword))
			throw new WrongIdPasswordException();
		this.password = newPassword;
	}

 

그리고 나서 플랫폼 트랜잭션 매니저 빈 설정

@Configuration
public class AppCtx {
	
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/spring5fs?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("spring5");
		ds.setPassword("spring5");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MemberDao memberDao() {
		return new MemberDao(dataSource());
	}
	
	@Bean 
	public PlatformTransactionManager transactionManager() {
		DataSourceTransactionManager tm = new DataSourceTransactionManager();
		tm.setDataSource(dataSource());
		return tm;
	}

 

실행 테스트

package main;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.AppCtx;
import spring.ChangePasswordService;
import spring.MemberNotFoundException;
import spring.WrongIdPasswordException;

public class MainForCPS {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = 
				new AnnotationConfigApplicationContext(AppCtx.class);
		ChangePasswordService cps =
				ctx.getBean("changePasswordService", ChangePasswordService.class);
		
		try {
			cps.changePassword("qqqq@wwe.com", "123", "111");
			System.out.println("암호를 변경했습니다.");
		}catch (MemberNotFoundException e) {
			System.out.println("회원 데이터가 존재하지 않습니다.");
		}catch (WrongIdPasswordException e) {
			System.out.println("암호가 올바르지 않습니다.");
		}
		ctx.close();
		

	}

}

 

 

 

 

오라클

PRIMARY KEY, FOREIGN KEY 

참조 대상 테이블을 부모, 참조하는 테이블을 자식으로 표현함

 

참조 대상이 될 DEPT_FK 테이블 생성

create table dept_fk (
deptno NUMBER(2) CONSTRAINT deptfk_deptno_pk PRIMARY key,
dname VARCHAR2(14),
loc VARCHAR2(13)
)

DEPT_FK 테이블의 DEPTNO 열을 참조하는 FOREIGN KEY 제약 조건을 정의한 EMP_FK 테이블 생성

CREATE table emp_fk(
empno NUMBER(4) CONSTRAINT empfk_empno_pk PRIMARY key,
ename VARCHAR2(10), 
job VARCHAR2(9),
mgr NUMBER(4),
hiredate date,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2) CONSTRAINT empfk_deptno_fk REFERENCES dept_fk(deptno)on delete set null
)

 

 

EMP_FK 테이블에 데이터 삽입 ( DEPENO 데이터가 아직 DEPT_FK 테이블에 없을 때 에러남 )

insert into emp_fk (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (9999, 'TEST_NNAME', 'TEST_JOB', null, '2001/01/01',3000,null,10)

 

DEPT_FK에 데이터 삽입 후 EMP_FK에 데이터 삽입해야 가능

insert into dept_fk (deptno, dname, loc)
VALUES(10, 'TEST_DNAME', 'TEST_LOC')
insert into emp_fk (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (9999, 'TEST_NNAME', 'TEST_JOB', null, '2001/01/01',3000,null,10)

 

 

현재 이 상태는 DEPT_FK 테이블에 10번 부서 데이터가 저장되어 있고 EMP_FK 테이블에는 이 10번 부서를 참조하는

데이터가 있다. 이 경우에는 DEPT_FK 테이블의 DEPTNO 열에 저장된 10번 부서 데이터는 삭제할 수 없다.

이유는 삭제하려는 DEPTNO 값을 참조하는 데이터가 존재하기 때문이다. 삭제하려면 방법이 2가지 정도 있다.

 

1. 참조하고 있는데 EMP_FK의 DEPENO가 10번인 데이터를 삭제한 후 DEPT_FK 테이블의 10번 부서 삭제

delete from emp_fk
where deptno = 10
delete from dept_fk
where deptno = 10

 

2. EMP_FK 테이블의 DEPTNO가 10번인 데이터를 다른 부서 번호나 NULL로 변경한 후 DEPT_FK 10번부서 삭제

delete from dept_fk
where deptno = 10

보통 2번 방법으로 많이 사용

 

 

 

기본 값을 정하는 DEFAULT

 

테이블을 생성할 때 DEFAULT 제약 조건 설정하기

create table table_default (
login_id VARCHAR2(20) CONSTRAINT tblck2_loginid_pk PRIMARY key,
login_pwd VARCHAR2(20) DEFAULT '1234',
tel VARCHAR2(20)
)

 

 

 

 

JSP 

 

세션 ( session )

세션은 클라이언트의 상태 값을 저장할 수 있고 서버에 값이 저장된다. 

세션을 사용하면 서버는 클라이언트의 상태 값을 유지할 수 있기 때문에, 인증된 사용자 정보를 유지하기 위한 목적으로

세션을 많이 사용 한다. ( 로그인 ) 

세션은 웹 브라우저마다 따로 존재하기 때문에 웹 브라우저와 관련된 1대 1정보를 저장하기 알맞은 장소이다.

 

세션 생성하기

 

 

세션 기본 객체 

세션의 기본객체는 request 기본객체, application 기본객체 ( 2개 많이 사용함 ) pageContext 기본객체와

마찬가지로 속성을 제공하며,

setAttribute(), getAttribute()등의 메서드를 사용하여 속성값을 저장하거나 읽어올 수 있다. 

세션 ID는 쿠키를 통해서 웹 브라우저에 전달된다. 

 

 

세션 기본 객체의 속성 사용

한번 생성된 세션은 지정된 유효 시간 동안 유지된다. 세션 기본객체는 웹 브라우저의 여러 요청을 처리하는 JSP 페이지

사이에서 공유된다.

 

예제)

setMember.jsp ( 세션에 저장 ) 

속성에 값을 저장할 때에는 request 기본객체와 마찬가지로 setAtrribute() 메서드를 사용하며, 속성 값을 사용할 때에는

getAttribute() 메서드를 사용 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
session.setAttribute("MEMBERID", "test");
session.setAttribute("NAME", "홍길동");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
세션에 저장함
</body>
</html>

getMember.jsp ( 속성 값 사용 ) 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%=session.getAttribute("MEMBERID") %><br/>
<%=session.getAttribute("NAME") %>


</body>
</html>

 

 

 

 

세션 종료

세션 유지할 필요가 없는 경우 session.invalidate() 메서드를 사용하면 세션 종료됨 ( 로그아웃 )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%
    session.invalidate();
    %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
세션이 종료됨
</body>
</html>

 

세션이 종료되면 기존에 사용하던 세션 기본 객체가 삭제되고, 다음에 세션을 사용할 때에는 새로운 세션 기본객체가 사용

 

 

 

세션의 유효 시간

세션은 최근 접근 시간이라는 개념을 갖고 있다. 세션 기본 객체가 사용될 때마다 세션은 최근 접근 시간은 갱싱된다.

유효 시간이 없는 상태에서 session.invalidate()를 명시적으로 실행하지 않는다면, 한번 생성된 세션 객체는 계속 메모리에 남아 있게 되고, 시간이 흐르게 되면 제거되지 않은 세션 객체 때문에 메모리 부족 현상을 발생하게 된다.

 

방법 1 : web.xml 파일에 유효 시간을 지정하는 방법 / 값의 단위는 분 아래 코드는 50분

 

방법 2 : 세션 기본 객체가 제공하는 setMaxInactiveInterval()메서드를 사용하는 방법 / 값의 단위는 초 단위 

              밑에 코드는 60분 

    <%
    session.setMaxInactiveInterval(60*60);
    %>

 

 

 

request.getSession()을 이용한 세션 생성

세션이 생성된 경우에만 세션 객체를 사용하고 싶은 경우에는 getSession() 메서드에 false를 파라미터로 전달해주면 된다. request.getSession(false) 를 실행하면 세션 객체가 생성된 경우에는 세션 객체를 리턴하고 세션 객체가 생성되어 있지 않은 경우에는 null을 리턴한다. 

 

 

 

 

세션을 사용한 인증 정보 유지 

1. 로그인에 성공하면 session 기본 객체의 특정 속성에 데이터를 기록한다.

2. 이후로 session 기본 객체의 특정 속성이 존재하면 로그인한 것으로 간주한다.

3. 로그아웃 할 경우 session.invalidate() 메서드를 호출하여 세션을 종료 한다. 

 

예제 )

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String id = request.getParameter("id");
	String password = request.getParameter("password");
	
	if(id.equals(password)){
		session.setAttribute("MEMBERID", id);
	

%>
<!DOCTYPE html>
<html>
<title>로그인 성공</title>
<head>
<meta charset="UTF-8">

</head>
<body>
로그인에 성공했습니다.
</body>
</html>
<%
}else{
%>
<script>
alert("로그인에 실패하였습니다.");
history.go(-1);
</script>
<%
}
%>

 

loginForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<title>로그인폼</title>
<head>
<meta charset="UTF-8">

</head>
<body>

<form action="<%= request.getContextPath() %>/member/sessionLogin.jsp" method="post">
아이디 <input type="text" name="id" size="10">
암호 <input type="password" name="password" size= "10">
<input type="submit" value="로그인">
</form>

</body>
</html>

 

loginCheck.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String memberId = (String)session.getAttribute("MEMBERID");
	boolean login = memberId == null ? false : true;
%>

<!DOCTYPE html>
<html>
<title>로그인 체크</title>
<head>
<meta charset="UTF-8">
</head>
<body>
<%
if(login){
%>
아이디 "<%= memberId %>"로 로그인 한 상태
<%
}else{
%>
로그인하지 않은 상태
<%
}
%>
</body>
</html>

 

logOut.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
session.invalidate();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그아웃</title>
</head>
<body>
로그아웃
</body>
</html>

 

 

loginform.jsp에서 입력 한 아이디, 비밀번호가 같아야 login.jsp로 이동되서 세션에 저장

 

 

세션 유지한 상태에서 loginCheck.jsp 실행시 로그인 유지상태 확인

 

logOut 실행 시 세션 종료 

 

 

 

 

필터 ( Filter )

클라이언트로부터 오는 요청(request)과 최종 자원 ( 서블릿, jsp, 기타 문서 ) 사이에 위치 클라이언트로부터 오는 요청정보를 알맞게 변경 가능 ( 웹페이지 서블릿 가운데에 위치 ) 서블릿 실행 전 필터 실행

 

클라이언트와 자원 사이에 한 개 의 필터만 존재 할 수 있는 것은 아니며, 여러 개의 필터가 모여 하나의 필터 체인을 형성하게 된다. 필터는 사용자 인증이나 권한 검사와 같은 기능을 구현할 때 사용할 수 있다. 

다이나믹 웹프로젝트에서 필터 생성 가능 ( 서블릿이랑 비슷한 옵션 ) 

 

 

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class LoginCheckFilter implements Filter {
    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpSession session = httpRequest.getSession(false);

        boolean login = false;
        if (session != null) {
            if (session.getAttribute("MEMBER") != null) {
                login = true;
            }
        }
        if (login) {
            chain.doFilter(request, response); // 다음 필터 처리
        } else {
            RequestDispatcher dispatcher = request
                    .getRequestDispatcher("/loginForm.jsp");
            dispatcher.forward(request, response);
        }
    }

    @Override
    public void destroy() {
    }
}

 

위에 코드에 메서드 기능은 

init() : 필터를 초기화할 때 호출된다.

doFilter() : 체인을 따라 다음에 존재하는 필터로 이동한다. 체인의 가장 마지막에는 클라이언트가 요청한 최종 자원이

위치한다. 

destroy() : 필터가 웹 컨테이너에서 삭제될 때 호출된다. 

 

 

필터 설정하기 : web.xml 이용

필터를 설정하는 방법은 두 가지가 있는데, 첫 번째 방법은 web.xml 파일에 관련 정보를 추가하는 것이며,

두 번째 방법은 @WebFilter 애노테이션을 사용하는 것이다.

 

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">



	<filter>
		<filter-name>LoginCheck</filter-name>
		<filter-class>filter.LoginCheckFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>LoginCheck</filter-name>
		<url-pattern>/board/*</url-pattern>
	</filter-mapping>

</web-app>

 

<filter> 태그는 사용될 필터를 지정하는 역할을 하며,

 

<filter-mapping> 태그는 특정 자원에 대해 어떤 필터를 사용할지를 지정한다. 위에 예제는 /board/ 로 시작하는 모든 확장자를 갖는 자원을 요청할 경우 FilterName 필터가 사용되도록 지정하고 있다.

 

<init-param> 태그는 필터의 init()메서드가 호출될 때 전달되는 파라미터 값이다. 이는 서블릿의 초기화 파라미터와 비슷한 역할을 하며 주로 필터를 사용하기 전에 초기화해야 하는 객체나 자원을 할당할 때 필요한 정보를 제공하기 위해 사용된다.

 

<url-pattern> 태그는 클라이언가 요청한 특정 URI에 대해서 필터링 할 때 사용된다. 

 

 

 

예제)

로그인 검사 필터

해당 필터는 로그인을 한 상태라면 필터 체인의 다음 필터로 이동하고 로그인을 하지 않은 상태로 판단되면 로그인 페이지로 이동하게 된다. 

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class LoginCheckFilter implements Filter {
    @Override
    public void init(FilterConfig config) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpSession session = httpRequest.getSession(false);

        boolean login = false;
        if (session != null) {
            if (session.getAttribute("MEMBER") != null) {
                login = true;
            }
        }
        if (login) {
            chain.doFilter(request, response);
        } else {
            RequestDispatcher dispatcher = request
                    .getRequestDispatcher("/loginForm.jsp");
            dispatcher.forward(request, response);
        }
    }

    @Override
    public void destroy() {
    }
}

 

web.xml

/board/*에 해당하는 요청을 보내면 LoginCheckFilter가 동작하게 되고, 세션에 "MEMBER"속성이 존재하지 않으면 /loginForm.jsp로 포워딩하게된다. 

<?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">



	<filter>
		<filter-name>LoginCheck</filter-name>
		<filter-class>filter.LoginCheckFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>LoginCheck</filter-name>
		<url-pattern>/board/*</url-pattern>
	</filter-mapping>

</web-app>

 

 

Member 속성이 존재하지 않은 상태에서 boardList.jsp 요청 

loginForm.jsp로 이동 board/ 뒤에는 아무거나 써도 됨  

 

로그인 처리 ( "Member" 속성 넣은 후 boardList.jsp 실행 ) 

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-09 59일차  (0) 2023.08.09
2023-08-08 58일차  (0) 2023.08.08
2023-08-04 56일차  (0) 2023.08.04
2023-08-03 55일차  (0) 2023.08.03
2023-08-02 54일차  (0) 2023.08.02

스프링

 

JDBCTemplate 연습 3 ( 방명록 ) Service

 

스프링 설정 클래스 ( AppCtx )

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import guestbook.dao.MessageDao;
import guestbook.service.DeleteMessageService;
import guestbook.service.GetMessageListService;
import guestbook.service.WriteMessageService;

@Configuration
public class AppCtx {
	
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/guestbook?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("jspexam");
		ds.setPassword("jsppw");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MessageDao messageDao() {
		return new MessageDao(dataSource());
	}
	
	@Bean
	public DeleteMessageService deleteMessageService() {
	return new DeleteMessageService();	
	}
	
	@Bean
	public GetMessageListService getMessageListService() {
		return new GetMessageListService();
	}
	
	@Bean
	public WriteMessageService writeMessageService() {
		return new WriteMessageService();
	}
	

}

 

 

 

DAO ( 주석 처린 된 곳은 JDBC )

package guestbook.dao;

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

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

import guestbook.model.Message;

public class MessageDao {
	
	private JdbcTemplate jdbcTemplate;
	
	public MessageDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	private Message makeMessageFromResultSet(ResultSet rs) throws SQLException {
		Message message = new Message();
		message.setId(rs.getInt("message_id"));
		message.setGuestName(rs.getString("guest_name"));
		message.setPassword(rs.getString("password"));
		message.setMessage(rs.getString("message"));
		return message;
	}
	
	
	public int insert(Message message) {
		String sql = "insert into guestbook_message " + 
			"(guest_name, password, message) values (?, ?, ?)";
		return jdbcTemplate.update(sql, 
				message.getGuestName(),
				message.getPassword(),
				message.getMessage()
				
				);
		
	}
	
//	public int insert(Connection conn, Message message) throws SQLException {
//		PreparedStatement pstmt = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"insert into guestbook_message " + 
//					"(guest_name, password, message) values (?, ?, ?)");
//			pstmt.setString(1, message.getGuestName());
//			pstmt.setString(2, message.getPassword());
//			pstmt.setString(3, message.getMessage());
//			return pstmt.executeUpdate();
//		} finally {
//			JdbcUtil.close(pstmt);
//		}
//	}

	public Message select(int messageId) {
		String sql = "select * from guestbook_message where message_id = ?";
		return jdbcTemplate.queryForObject(sql, 
				(ResultSet rs, int rowNum) -> {
					return makeMessageFromResultSet(rs);
				} ,messageId);
		
	}
	
//	public Message select(Connection conn, int messageId) throws SQLException {
//		PreparedStatement pstmt = null;
//		ResultSet rs = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"select * from guestbook_message where message_id = ?");
//			pstmt.setInt(1, messageId);
//			rs = pstmt.executeQuery();
//			if (rs.next()) {
//				return makeMessageFromResultSet(rs);
//			} else {
//				return null;
//			}
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(pstmt);
//		}
//	}


	public int selectCount() {
		String sql = "select count(*) from guestbook_message";
		Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
				return count;
	}
	
//	public int selectCount(Connection conn) throws SQLException {
//		Statement stmt = null;
//		ResultSet rs = null;
//		try {
//			stmt = conn.createStatement();
//			rs = stmt.executeQuery("select count(*) from guestbook_message");
//			rs.next();
//			return rs.getInt(1);
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(stmt);
//		}
//	}

	public List<Message> selectList(int firstRow, int endRow){
		String sql = "select * from guestbook_message " + 
				"order by message_id desc limit ?, ?";
		
		List<Message> result = jdbcTemplate.query(sql, 
				(rs, rowNum) -> makeMessageFromResultSet(rs), 
				firstRow - 1,
				endRow - firstRow + 1);
		
		return result;
	}
	
//	public List<Message> selectList(Connection conn, int firstRow, int endRow) 
//			throws SQLException {
//		PreparedStatement pstmt = null;
//		ResultSet rs = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"select * from guestbook_message " + 
//					"order by message_id desc limit ?, ?");
//			pstmt.setInt(1, firstRow - 1);
//			pstmt.setInt(2, endRow - firstRow + 1);
//			rs = pstmt.executeQuery();
//			if (rs.next()) {
//				List<Message> messageList = new ArrayList<Message>();
//				do {
//					messageList.add(makeMessageFromResultSet(rs));
//				} while (rs.next());
//				return messageList;
//			} else {
//				return Collections.emptyList();
//			}
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(pstmt);
//		}
//	}

	public int delete1(int messageId) {
		String sql = "delete from guestbook_message where message_id = ?";
		return jdbcTemplate.update(sql, messageId);
	
	}
	
//	public int delete(Connection conn, int messageId) throws SQLException {
//		PreparedStatement pstmt = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"delete from guestbook_message where message_id = ?");
//			pstmt.setInt(1, messageId);
//			return pstmt.executeUpdate();
//		} finally {
//			JdbcUtil.close(pstmt);
//		}
//	}

}

 

DeleteMessageService ( ID값, passwrd 값 비교 후 맞으면 게시물 삭제 ) 

package guestbook.service;

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.dao.MessageDao;
import guestbook.model.Message;

public class DeleteMessageService {
	
	// 싱글톤
//	private static DeleteMessageService instance = new DeleteMessageService();
//
//	public static DeleteMessageService getInstance() {
//		return instance;
//	}
//
//	private DeleteMessageService() {
//	}
	@Autowired
	private MessageDao messageDao;

	public void deleteMessage(int messageId, String password) {
	
			
			Message message = messageDao.select(messageId);
			if (message == null) {
				throw new MessageNotFoundException("메시지 없음");
			}
			if (!message.matchPassword(password)) {
				throw new InvalidPassowrdException("bad password");
			}
			messageDao.delete1(messageId);
			

	}
}

 

결과 테스트 ( 9 id값 가진 게시물 패스워드 맞으면 삭제 ) 

public class MainTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext(AppCtx.class);
		
		
		DeleteMessageService ds = ctx.getBean("deleteMessageService",DeleteMessageService.class);
		
		ds.deleteMessage(9, "111");
        }
        }

 

 

GetMessageListService ( 방명록 메시지를 페이지 단위로 조회 ) 페이징

package guestbook.service;

import java.util.Collections;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.dao.MessageDao;
import guestbook.model.Message;

public class GetMessageListService {
	
	@Autowired
	private MessageDao messageDao; 

	// 한 페이지에 표시될 메시지 수
	private static final int MESSAGE_COUNT_PER_PAGE = 3;

	public MessageListView getMessageList(int pageNumber) {
		int currentPageNumber = pageNumber; // 요청받은 페이지 번호

		// 전체 메시지의 수를 가져옴
		int messageTotalCount = messageDao.selectCount();

		List<Message> messageList = null;
		int firstRow = 0;
		int endRow = 0;
		if (messageTotalCount > 0) {
			// 요청한 페이지의 첫 번째 메시지와 마지막 메시지의 인덱스를 계산
			firstRow = (pageNumber - 1) * MESSAGE_COUNT_PER_PAGE + 1;
			endRow = firstRow + MESSAGE_COUNT_PER_PAGE - 1;
			// 메시지를 firstRow부터 endRow까지 조회하여 리스트로 가져옴
			messageList = messageDao.selectList(firstRow, endRow);
		} else {
			// 전체 메시지가 없는 경우 (빈 리스트)
			currentPageNumber = 0;
			messageList = Collections.emptyList();
		}

		// 조회된 메시지 리스트와 페이징에 필요한 정보들을 MessageListView 객체로 생성하여 반환
		return new MessageListView(
			messageList, // 조회된 메시지 리스트
			messageTotalCount, // 전체 메시지 수
			currentPageNumber, // 현재 페이지 번호
			MESSAGE_COUNT_PER_PAGE, // 한 페이지에 표시될 메시지 수
			firstRow, // 현재 페이지의 첫 번째 메시지 인덱스
			endRow // 현재 페이지의 마지막 메시지 인덱스
		);
	} 
}

 

결과 테스트 ( MessageListView mlv = gs.getMessageList(1);은 1페이지 출력  ) 

public class MainTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext(AppCtx.class);
		
		
		// 페이지 읽어오기
		GetMessageListService gs = ctx.getBean("getMessageListService", GetMessageListService.class);
		
		MessageListView mlv = gs.getMessageList(1);
		List<Message> list = mlv.getMessageList();
		for(Message msg : list) {
			System.out.println(msg);
		}
        }
        }

 

WriteMessageService ( 추가 ) 

package guestbook.service;

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.dao.MessageDao;
import guestbook.model.Message;

public class WriteMessageService {
	@Autowired
	private MessageDao messageDao;

	public void write(Message message) {



			messageDao.insert(message);

	}

}

 

결과 테스트

public class MainTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext(AppCtx.class);
		
		
		// 페이지 읽어오기
		WriteMessageService ws = ctx.getBean("writeMessageService", WriteMessageService.class);
		
		
		Message message = new Message("홍금보", "123", "홍홍홍");
		ws.write(message);
        }
        }

 

 

 

 

 

커맨드 핸들러 ( CommandHandler )_방명록_JSP 실습

 

1. CommandHandler.java ( 인터페이스 ), ControllerUsingURI.java ( 서블릿 ) 환경 설정

( 코드 그대로 사용 )

 

 

CommandHandler.java

package command;

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

public interface CommandHandler {
	public String process(HttpServletRequest req, HttpServletResponse res) throws Exception;
	
	
}

 

ControllerUsingURI.java

package command;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.AppCtx;

public class ControllerUsingURI extends HttpServlet {
	
	// 어디서든 사용할 수 있게 설정
	//public static ApplicationContext ctx;
	
	// @Autowired
	// BoardService boardService;
	ApplicationContext ctx;
	
    // <커맨드, 핸들러인스턴스> 매핑 정보 저장
    private Map<String, String> commandHandlerMap = 
    		new HashMap<>();
    // 서블릿 초기화 메서드
    public void init() throws ServletException {
    	
    	ctx = new AnnotationConfigApplicationContext(AppCtx.class);
    	
     	// configFile 초기화 파라미터를 읽어온다.
        // 이 값을 이용해서 설정 파일 경로를 구한다.
        String configFile = getInitParameter("configFile");
        System.out.println(configFile);
        Properties prop = new Properties();
        String configFilePath = getServletContext().getRealPath(configFile);
        System.out.println(configFilePath);
        // 설정 파일로부터 매핑 정보를 읽어와 Properties 객체에 저장한다.
        // Properties는 (이름, 값) 목록을 갖는 클래스로서,
        // 이 경우에는 프로퍼티 이름을 커맨드 이름으로 사용하고
        // 값을 클래스 이름으로 사용한다.
        try (FileReader fis = new FileReader(configFilePath)) { // 파일 읽기
        	// 설정 파일을 읽어서 Properties 객체에 로드 ( 맵에 보관 ) 
            prop.load(fis);
        } catch (IOException e) {
            throw new ServletException(e);
        }
        // Properties에 저장된 각 프로퍼티의 키에 대해 다음 작업을 반복한다.
        Iterator keyIter = prop.keySet().iterator();
        while (keyIter.hasNext()) {
        	// 1. 프로퍼티 이름을 커맨드 이름으로 사용한다.
            String command = (String) keyIter.next();
            // 2. 커맨드 이름에 해당하는 핸들러 클래스 이름을 Properties에서 구한다.
            String handlerClassName = prop.getProperty(command);
            commandHandlerMap.put(command, handlerClassName);
//            try {
//            	// 3. 핸들러 클래스 이름을 이용해서 Class 객체를 구한다.
//                Class<?> handlerClass = Class.forName(handlerClassName);
//                // 4. Class로부터 핸들러 객체를 생성한다. 
//                CommandHandler handlerInstance = 
//                        (CommandHandler) handlerClass.newInstance();
//             // 5. commandHandlerMap에 (커맨드, 핸들러 객체)에 대한 매핑 정보를 저장한다.
//                commandHandlerMap.put(command, handlerInstance);
//            } catch (ClassNotFoundException | InstantiationException 
//            		| IllegalAccessException e) {
//                throw new ServletException(e);
//            }
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        process(request, response);
    }

    protected void doPost(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }
    
    // 클라이언트로부터 들어오는 HTTP 요청에 대해 처리를 수행
    // 그에 맞는 핸들러를 호출하여 요청을 처리하고 결과를 뷰 페이지에 전달
    private void process(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
    	// 클라이언트가 요청한 URI를 가져온다.
		String command = request.getRequestURI();
		// 요청된 URI가 웹 어플리케이션의 Context Path(컨텍스트 경로)로 시작한다면,
		// Context Path 부분을 제거하여 실제로 처리할 명령어를 추출
		// 예)/hello.do 추출
		if (command.indexOf(request.getContextPath()) == 0) {
			command = command.substring(request.getContextPath().length());
		}
		System.out.println(command);
		// 추출된 명령어를 사용하여 commandHandlerMap에서 해당 커맨드에 대응하는 핸들러를 가져온다.
		// commandHandlerMap은 init() 메서드에서 설정 파일로부터 읽어온 커맨드와 핸들러 클래스를 매핑한 맵
//        CommandHandler handler = commandHandlerMap.get(command);
//        // 만약 해당 명령어에 대응하는 핸들러가 없다면, 기본적으로 NullHandler를 사용
//        if (handler == null) {
//            handler = new NullHandler();
//        }
        // 찾아낸 핸들러를 사용하여 실제 요청 처리를 수행
        // 핸들러의 process() 메서드를 호출하여 요청 처리 결과로 뷰 페이지의 경로를 가져온다.
        // 최종적으로 클라이언트에게 보여질 JSP 페이지의 위치를 나타낸다.
        String handler = commandHandlerMap.get(command);
        System.out.println(handler);
        // 인터페이스 다형성
        CommandHandler helloHandler = ctx.getBean(handler, CommandHandler.class);
		String viewPage = null;
        try {
            viewPage = helloHandler.process(request, response);
            
        } catch (Throwable e) {
            throw new ServletException(e);
        }
        // 만약 뷰 페이지 경로가 존재한다면, RequestDispatcher를 사용하여 해당 뷰 페이지로 포워딩
        // 즉, 요청된 작업의 처리 결과를 클라이언트에게 보여줄 JSP 페이지로 이동하게 된다.
        if (viewPage != null) {
	        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
	        dispatcher.forward(request, response);
        }
    }
}

 

 

2. web.xml 파일 : 서블릿 name, class, mapping 설정 확인 

<?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">

	
	<servlet>
		<servlet-name>ControllerUsingURI</servlet-name>
		<servlet-class>command.ControllerUsingURI</servlet-class>
		<init-param>
			<param-name>configFile</param-name>
			<param-value>
                /WEB-INF/commandHandlerURI.properties
            </param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>ControllerUsingURI</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

</web-app>

 

 

 

3. Handler.java 파일 작성

ListHandler

package command;

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

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.service.GetMessageListService;
import guestbook.service.MessageListView;

public class ListHandler implements CommandHandler {
	

	
	@Autowired
	private GetMessageListService getMessageListService;

	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws Exception {
	
		String pageNumberStr = req.getParameter("page");
		int pageNumber = 1;
		if (pageNumberStr != null) {
			pageNumber = Integer.parseInt(pageNumberStr);
		}
	MessageListView viewData = 
			getMessageListService.getMessageList(pageNumber);
	
	req.setAttribute("viewData", viewData);
	return "/WEB-INF/view/list.jsp";
	

}
	
	
}

 

WriteMessageHandler

package command;

import java.io.UnsupportedEncodingException;

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

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.model.Message;
import guestbook.service.WriteMessageService;



public class WriteMessageHandler implements CommandHandler {

	@Autowired
	private WriteMessageService writeMessageService;
	
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws UnsupportedEncodingException {

		req.setCharacterEncoding("utf-8");

		String guestName = req.getParameter("guestName");
		String password = req.getParameter("password");
		String message = req.getParameter("message");
		
		Message msg = new Message(guestName, password, message);
		
		writeMessageService.write(msg);

		
		return "/WEB-INF/view/writeMessage.jsp";
	}

}

 

 

ConfirmDeletionHandler ( 삭제 여부 비밀번호로 확인만 하는 페이지  ) 

package command;

import java.io.UnsupportedEncodingException;

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

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.service.DeleteMessageService;



public class ConfirmDeletionHandler implements CommandHandler {

	@Autowired
	private DeleteMessageService deleteMessageService;
	
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws UnsupportedEncodingException {


		String messageId = req.getParameter("messageId");
		req.setAttribute("messageId", messageId);
		
		return "/WEB-INF/view/confirmDeletion.jsp";
	}

}

 

DeleteMessageHandler ( 실제로 삭제 처리 하는 곳 ) 

package command;

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

import org.springframework.beans.factory.annotation.Autowired;

import guestbook.service.DeleteMessageService;
import guestbook.service.InvalidPassowrdException;

public class DeleteMessageHandler implements CommandHandler {
	@Autowired
	private DeleteMessageService deleteMessageService;
	
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) {
		int messageId = Integer.parseInt(req.getParameter("messageId"));
		String password = req.getParameter("password");
		String invalidPassowrd = "no";
		try {
			deleteMessageService.deleteMessage(messageId, password);
		} catch(InvalidPassowrdException ex) {
			invalidPassowrd = "yes";
		} 
		req.setAttribute("invalidPassowrd", invalidPassowrd);
		return "/WEB-INF/view/deleteMessage.jsp";
	}

}

 

 

4. 스프링 설정 클래스 @Bean 등록 ( 핸들러에서 Service 사용, 핸들러도 @Bean 등록 ) 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import command.ConfirmDeletionHandler;
import command.DeleteMessageHandler;
import command.ListHandler;
import command.WriteMessageHandler;
import guestbook.dao.MessageDao;
import guestbook.service.DeleteMessageService;
import guestbook.service.GetMessageListService;
import guestbook.service.WriteMessageService;

@Configuration
public class AppCtx {
	
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/guestbook?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("jspexam");
		ds.setPassword("jsppw");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MessageDao messageDao() {
		return new MessageDao(dataSource());
	}
	
	@Bean
	public DeleteMessageService deleteMessageService() {
	return new DeleteMessageService();	
	}
	
	@Bean
	public GetMessageListService getMessageListService() {
		return new GetMessageListService();
	}
	
	@Bean
	public WriteMessageService writeMessageService() {
		return new WriteMessageService();
	}
	
	
	@Bean
	public ListHandler listHandler() {
		return new ListHandler();
	}
	
	@Bean
	public WriteMessageHandler writeMessageHandler() {
		return new WriteMessageHandler();
	}
	
	@Bean
	public ConfirmDeletionHandler confirmDeletionHandler() {
		return new ConfirmDeletionHandler();
	}
	
	@Bean
	public DeleteMessageHandler deleteMessageHandler() {
		return new DeleteMessageHandler();
	}
}

 

 

5. commandHandlerURI.properties : /hello.do=helloHandler ( 주소 지정 및 @Bean 변수명 )

/hello.do=helloHandler
/list.do=listHandler
/writeMessage.do=writeMessageHandler
/confirmDeletion.do=confirmDeletionHandler
/deleteMessage.do=deleteMessageHandler

 

 

6. JSP에서 자바 코드 없이 작성 ( jstl : 가능 )  / ( 경로 WEB-INF => view디렉터리 )

List.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>




<html>
<head>
	<title>방명록 메시지 목록</title>
</head>
<body>

<form action="writeMessage.do" method="post">
이름: <input type="text" name="guestName"> <br>
암호: <input type="password" name="password"> <br>
메시지: <textarea name="message" cols="30" rows="3"></textarea> <br>
<input type="submit" value="메시지 남기기" />
</form>
<hr>
<c:if test="${viewData.isEmpty()}">
등록된 메시지가 없습니다.
</c:if>

<c:if test="${!viewData.isEmpty()}">
<table border="1">
	<c:forEach var="message" items="${viewData.messageList}">
	<tr>
		<td>
		메시지 번호: ${message.id} <br/>
		손님 이름: ${message.guestName} <br/>
		메시지: ${message.message} <br/>
		<a href="confirmDeletion.do?messageId=${message.id}">[삭제하기]</a>
		</td>
	</tr>
	</c:forEach>
</table>

<c:forEach var="pageNum" begin="1" end="${viewData.pageTotalCount}">
<a href="list.jsp?page=${pageNum}">[${pageNum}]</a> 
</c:forEach>

</c:if>
</body>
</html>

writeMessage.jsp

<%@ page contentType="text/html; charset=utf-8" %>

<html>
<head>
	<title>방명록 메시지 남김</title>
</head>
<body>
방명록에 메시지를 남겼습니다.
<br/>
<a href="list.do">[목록 보기]</a>
</body>
</html>

 

confirmDeletion.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<html>
<head>
    <title>방명록 메시지 삭제 확인</title>
</head>
<body>

<form action="deleteMessage.do" method="post">
<input type="hidden" name="messageId" value="${messageId}">
메시지를 삭제하시려면 암호를 입력하세요:<br>
암호: <input type="password" name="password"> <br>
<input type="submit" value="메시지 삭제하기">
</form>
</body>
</html>

 

deleteMessage.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
	<title>방명록 메시지 삭제함</title>
</head>
<body>
<c:choose>

      <c:when test="${invalidPassowrd eq 'no'}">
      		<p> 메시지를 삭제하였습니다. </p>
      </c:when> 

      <c:otherwise>
      		<p> 입력한 암호가 올바르지 않습니다. 암호를 확인해주세요. </p>
      </c:otherwise> 
</c:choose> 
<br/>
<a href="list.do">[목록 보기]</a>
</body>
</html>

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-08 58일차  (0) 2023.08.08
2023-08-07 57일차  (0) 2023.08.07
2023-08-03 55일차  (0) 2023.08.03
2023-08-02 54일차  (0) 2023.08.02
2023-08-01 53일차  (0) 2023.08.01

+ Recent posts