spring - 메이븐

오늘·2021년 6월 7일
0

웹 페이지 연습

목록 보기
27/35

메이븐이란

  • Apache 프로젝트로 편리한 '프로젝트 관리 툴'
  • 소스코드로부터 배포 가능한 산출물(Artifact)를 빌드(Build)하는 '빌드툴(Build Tool)'
  • 프로젝트 종속 라이브러리들과 그 라이브러리에 의존하는 Dependency 자원까지 관리 가능
  • 프로젝트 전반의 리소스 관리와 설정 파일 그리고 이와 관련된 표준 디렉토리 구조를 처음부터 일관된 형태로 구성하여 관리할 수 있다.

의존성

  • 라이브러리 다운로드 자동화
  • 선언적
    -> 메이븐은 명령식(명령어를 입력해 사용하는 것)이 아니다
    -> 사용되는 jar 파일들을 다운받을 경로를 지정하고, 어느 버젼을 받을 것인지 명시만 하면 코딩을 따로 하지 않아도 메이븐이 알아서 관리
    -> 재 다운로드, 최신 버전 설치까지 관리해준다

STS(Spring Tool Suite)

  • 이클립스를 기반으로 만들어진 스프링 기반 애플리케이션 개발용 도구
  • 참고한 다운로드 방법 : zincod.tistory
    (지금껏 실습에 사용한 이클립스가 옥시젼으로 좀 낮은 버젼이라 1,2 번 방법으로 하지 못하고 3번 방법으로 다운로드함)

메이븐 프로젝트

구조와 구성 요소

pom.xml 구성 요소

  • pom.xml의 프로젝트 정보 설정 태그 구성 요소

  • pom.xml의 dependencies 정보 설정 태그 구성 요소


스프링 프로젝트

만들기

  1. 메뉴에서 new > project > Spring Legacy Project
  2. 프로젝트 명(ex> pro27)을 적고 템플릿으로 Spring MVC Project 선택
  3. 다운로드 메시지창(Spring MVC Project requires a download of...)이 나타나면 yes
  4. 패키지 이름 표시하기 (세번째 단계의 패키지 이름. ex> com.spring.pro27)

STS 프로젝트 구조


스프링 프로젝트 실행하기

web.xml

...
	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<!-- 스프일 실행시 servlet-context.xml 의 설정정보를 읽어 들이기 -->
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
...

servlet-context.xml

...
	<!-- Jsp에서 사용될 자바 스크립트나 이미지 파일의 경로 지정 -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- 뷰 리졸버 빈을 생성하면서 응답할 Jsp의 경로 지정 -->
	<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.myspring.pro27" />
...

HomeController.java

모든 요청에 대해 home() 메소드를 호출, 요청 시각을 home.jsp로 포워딩 한다

package com.myspring.pro27;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

// 어노테이션 적용
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	
	// 모든 요청에 대해 home() 메소드 호출
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		// 브라우저에서 요청한 시간을 jsp로 전달
		model.addAttribute("serverTime", formattedDate );
		
		// 뷰 리졸버로 jsp 이름 반환
		return "home";
	}	
}

home.jsp

컨트롤러에서 전달된 요청 시간을 출력하도록 작성

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
<h1>
	Hello world!  
</h1>

<!-- ${serverTime} : '브라우저에서 값을 요청한 시간'을 브라우저에 출력 -->
<P>  The time on the server is ${serverTime}. </P>
</body>
</html>

실행

서버를 실행시킨 후 http://localhost:8700/pro27 로 요청

근데 한글이 깨지니까 수정

web.xml 수정

...
    <!-- 한글깨짐 해결하기 -->
    <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>
        <init-param>  
           <param-name>forceEncoding</param-name>  
           <param-value>true</param-value>  
        </init-param> 
    </filter>
    
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

실행

다시 실행시켜보니 원활하게 한글이 잘 출력되는 모습을 확인할 수 있었다..

지금은 web.xml의 가장 마지막 부분에 인코딩코드를 집어넣었는데, 이게 찾다보니까 만약 다른 필터를 사용한다면 (예를 들어 springSecurityFilterChain) 그보다 앞에 이 인코딩 필터(위의 한글필터)를 적용해줘야 한다고 한다. 값을 받아서 먼저 문자처리부터 하고 그 다음 필터를 적용시켜야 제대로 된다고. 이건 공부하면서 뭔 말인지 더 이해해봐야겠다.


STS 환경에서 마이바티스

pom.xml 확인

사용하려는 폴더 안에 있는지 확인한다

오라클 사용시

  • 오픈 소스가 아닌 오라클을 사용하려면 드라이버를 직접 다운로드 하여 lib 폴더에 복사 붙여넣기 (오픈소스인 MySQL은 상관 없다)
    오라클 jar이 있는 위치에 가서 사용할 것 복사

    lib 폴더를 만들고 그 밑에 붙여넣기

pom.xml에 필요한 jar 파일 명시

  • pom.xml 안에 <dependency> 태그를 이용해 설치가 필요한 jar 파일을 명시 (Test 표시가 되어있는 곳 밑에 표시하면된다.
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
		
		<!-- 데이터 소스 관련 라이브러리 설정 -->
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>2.2</version>
		</dependency>
		
		<!-- 마이바티스 관련 라이브러리 설정 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.1.0</version>
		</dependency>
		
		<!-- 로컬에 설치한 오라클 드라이버 lib를 설정한다 -->
		<dependency>
			<groupId>jdbc.oracle</groupId>
			<artifactId>OracleDriver</artifactId>
			<version>12.1.0.2.0</version>
			<scope>system</scope>
          		<!-- <systemPath>로 로컬에 설치한 위치 지정 / ${basedir}은 프로젝트의 루트 디렉토리 -->
			<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/ojdbc6.jar</systemPath>
		</dependency>

작성 후 저장해주면 <dependency> 태그로 설정한 것들이 알아서 다운로드가 진행되는 모습을 확인할 수 있었다.

만약 오라클이 아니라 MySQL을 사용한다면?

<!-- 로컬에 설치한 오라클 드라이버 lib를 설정한다 -->
<dependency>
	<groupId>jdbc.oracle</groupId>
	<artifactId>OracleDriver</artifactId>
	<version>12.1.0.2.0</version>
	<scope>system</scope>
	<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/ojdbc6.jar</systemPath>          
이 부분을
  
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.29</version>
이런 식으로 작성하면 된다고 하는데..

마이바티스 관련 xml 파일을 추가

  • config/jdbc 폴더를 새로 만들고 jbc.properties 파일 추가하기
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.username=System
jdbc.password=비밀번호
  • action-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
 xsi:schemaLocation="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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans">

	<bean id="propertyPlaceholderConfigurer"
	class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
	<value>/WEB-INF/config/jdbc/jdbc.properties</value>
	</property>
	</bean>

 	<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
		<property name="driver" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation"
			value="classpath:mybatis/model/modelConfig.xml" />
		<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml" />
	</bean>

	<bean id="sqlSession"
		class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
	</bean>
</beans>

web.xml에서 action-mybatis.xml을 읽을 수 있게끔 수정

  • 설정 파일 중 읽어들이는 첫번째가 web.xml이니까 다른 사용하려는 파일들을 web.xml에 묶어줘야 한다.
  • root-context.xml 대신에 action-mybatis.xml로 연결
	<context-param>
		<param-name>contextConfigLocation</param-name>
      	<!--<param-value>/WEB-INF/spring/root-context.xml</param-value>-->
		<param-value>/WEB-INF/spring/action-mybatis.xml</param-value>
	</context-param>

mappers, model 패키지

파일 모양

  • 사용할 sql을 적어놓은 매퍼 파일 : member.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="mapper.member">
	<resultMap id="memResult" type="memberVO">
		<result property="id" column="id" />
        <result property="pwd" column="pwd" />
        <result property="name" column="name" />
        <result property="email" column="email" />
        <result property="joinDate" column="joinDate" />
	</resultMap>

	<select id="selectAllMemberList" resultMap="memResult">
      <![CDATA[
         select * from t_member	order by joinDate desc	 	
      ]]>
	</select>
    
     <insert id="insertMember"  parameterType="memberVO">
		<![CDATA[
		 insert into t_member(id,pwd, name, email)
		 values(#{id}, #{pwd}, #{name}, #{email})
		]]>      
	</insert>
	
   
   <update id="updateMember"  parameterType="memberVO">
     <![CDATA[
	     update t_member
	     set pwd=#{pwd}, name=#{name}, email=#{email}
	     where
	     id=#{id}
      ]]>      
   </update> 
     
   <delete id="deleteMember"  parameterType="String">
	<![CDATA[
	   delete from  t_member
	   where
	   id=#{id}
	]]>      
  </delete>
  <select id="loginById"  resultType="memberVO"   parameterType="memberVO" >
	<![CDATA[
		select * from t_member	
		where id=#{id} and pwd=#{pwd}		
	]]>
  </select>
</mapper>
  • MemberVO에 대한 alias를 설정 modelConfig.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.myspring.pro27.member.vo.MemberVO"  alias="memberVO" />
	</typeAliases>
</configuration>

자바 클래스와 jsp 구현 (전에 사용했던거 가져오기)

자바 클래스 파일 위치

.jsp 파일 위치

MemberControllerImpl.java

package com.myspring.pro27.member.controller;

import java.util.List;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.myspring.pro27.member.service.MemberService;
import com.myspring.pro27.member.vo.MemberVO;



@Controller("memberController")
public class MemberControllerImpl   implements MemberController {
	private static final Logger logger = LoggerFactory.getLogger(MemberControllerImpl.class);
	@Autowired
	private MemberService memberService;
	@Autowired
	private MemberVO memberVO ;
	
	@Override
	@RequestMapping(value="/member/listMembers.do" ,method = RequestMethod.GET)
	public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		
		logger.info("viewName: "+ viewName);
		logger.debug("viewName: "+ viewName);
		
		List membersList = memberService.listMembers();
		ModelAndView mav = new ModelAndView(viewName);
		mav.addObject("membersList", membersList);
		
		return mav;
	}

	@Override
	@RequestMapping(value="/member/addMember.do" ,method = RequestMethod.POST)
	public ModelAndView addMember(@ModelAttribute("member") MemberVO member,
			                  HttpServletRequest request, HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("utf-8");
		
		int result = 0;
		result = memberService.addMember(member);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		
		return mav;
	}
	
	@Override
	@RequestMapping(value="/member/removeMember.do" ,method = RequestMethod.GET)
	public ModelAndView removeMember(@RequestParam("id") String id, 
			           HttpServletRequest request, HttpServletResponse response) throws Exception{
		request.setCharacterEncoding("utf-8");
		
		memberService.removeMember(id);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		
		return mav;
	}
	
	@RequestMapping(value = { "/member/loginForm.do", "/member/memberForm.do" }, method =  RequestMethod.GET)
	public ModelAndView form(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		ModelAndView mav = new ModelAndView();
		mav.setViewName(viewName);
		
		return mav;
	}
	
	@Override
	@RequestMapping(value = "/member/login.do", method = RequestMethod.POST)
	public ModelAndView login(@ModelAttribute("member") MemberVO member,
				              RedirectAttributes rAttr,
		                       HttpServletRequest request, HttpServletResponse response) throws Exception {
	ModelAndView mav = new ModelAndView();
	memberVO = memberService.login(member);
	if(memberVO != null) {
		    HttpSession session = request.getSession();
		    session.setAttribute("member", memberVO);
		    session.setAttribute("isLogOn", true);
		    mav.setViewName("redirect:/member/listMembers.do");
	}else {
		    rAttr.addAttribute("result","loginFailed");
		    mav.setViewName("redirect:/member/loginForm.do");
	}
	return mav;
	}

	@Override
	@RequestMapping(value = "/member/logout.do", method =  RequestMethod.GET)
	public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		session.removeAttribute("member");
		session.removeAttribute("isLogOn");
		ModelAndView mav = new ModelAndView();
		mav.setViewName("redirect:/member/listMembers.do");
		return mav;
	}	

	@RequestMapping(value = "/member/*Form.do", method =  RequestMethod.GET)
	private ModelAndView form(@RequestParam(value= "result", required=false) String result,
						       HttpServletRequest request, 
						       HttpServletResponse response) throws Exception {
		String viewName = (String)request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView();
		mav.addObject("result",result);
		mav.setViewName(viewName);
		
		return mav;
	}
	

	private String getViewName(HttpServletRequest request) throws Exception {
		String contextPath = request.getContextPath();
		String uri = (String) request.getAttribute("javax.servlet.include.request_uri");
		if (uri == null || uri.trim().equals("")) {
			uri = request.getRequestURI();
		}

		int begin = 0;
		if (!((contextPath == null) || ("".equals(contextPath)))) {
			begin = contextPath.length();
		}

		int end;
		if (uri.indexOf(";") != -1) {
			end = uri.indexOf(";");
		} else if (uri.indexOf("?") != -1) {
			end = uri.indexOf("?");
		} else {
			end = uri.length();
		}

		String viewName = uri.substring(begin, end);
		if (viewName.indexOf(".") != -1) {
			viewName = viewName.substring(0, viewName.lastIndexOf("."));
		}
		if (viewName.lastIndexOf("/") != -1) {
			// /member/listMembers.do로 요청할 경우 member/listMember를 파일 이름으로 가져온다
			viewName = viewName.substring(viewName.lastIndexOf("/", 1), viewName.length());
		}
		return viewName;
	}
}

MemberDAOImpl.java

package com.myspring.pro27.member.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.myspring.pro27.member.vo.MemberVO;

@Repository("memberDAO")
public class MemberDAOImpl implements MemberDAO {
	@Autowired
	private SqlSession sqlSession;

	@Override
	public List selectAllMemberList() throws DataAccessException {
		List<MemberVO> membersList = null;
		membersList = sqlSession.selectList("mapper.member.selectAllMemberList");
		return membersList;
	}

	@Override
	public int insertMember(MemberVO memberVO) throws DataAccessException {
		int result = sqlSession.insert("mapper.member.insertMember", memberVO);
		return result;
	}

	@Override
	public int deleteMember(String id) throws DataAccessException {
		int result = sqlSession.delete("mapper.member.deleteMember", id);
		return result;
	}
	
	@Override
	public MemberVO loginById(MemberVO memberVO) throws DataAccessException{
		  MemberVO vo = sqlSession.selectOne("mapper.member.loginById",memberVO);
		return vo;
	}
}

MemberServiceImpl.java

package com.myspring.pro27.member.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.myspring.pro27.member.dao.MemberDAO;
import com.myspring.pro27.member.vo.MemberVO;


@Service("memberService")
@Transactional(propagation = Propagation.REQUIRED)
public class MemberServiceImpl implements MemberService {
	@Autowired
	private MemberDAO memberDAO;

	@Override
	public List listMembers() throws DataAccessException {
		List membersList = null;
		membersList = memberDAO.selectAllMemberList();
		return membersList;
	}

	@Override
	public int addMember(MemberVO member) throws DataAccessException {
		return memberDAO.insertMember(member);
	}

	@Override
	public int removeMember(String id) throws DataAccessException {
		return memberDAO.deleteMember(id);
	}
	
	@Override
	public MemberVO login(MemberVO memberVO) throws Exception{
		return memberDAO.loginById(memberVO);
	}
}

MemberVO.java

package com.myspring.pro27.member.vo;

import java.sql.Date;

import org.springframework.stereotype.Component;

@Component("memberVO")
public class MemberVO {
	private String id;
	private String pwd;
	private String name;
	private String email;
	private Date joinDate;

	public MemberVO() {
		
	}

	public MemberVO(String id, String pwd, String name, String email) {
		this.id = id;
		this.pwd = pwd;
		this.name = name;
		this.email = email;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getJoinDate() {
		return joinDate;
	}

	public void setJoinDate(Date joinDate) {
		this.joinDate = joinDate;
	}
}

listMembers.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<%  request.setCharacterEncoding("UTF-8"); %>


<html>
<head>
<meta charset=UTF-8">
<title>회원 정보 출력창</title>
</head>
<body>
	<table border="1" align="center" width="80%">
		<tr align="center" bgcolor="lightgreen">
			<td><b>아이디</b></td>
			<td><b>비밀번호</b></td>
			<td><b>이름</b></td>
			<td><b>이메일</b></td>
			<td><b>가입일</b></td>
			<td><b>삭제</b></td>
		</tr>

		<c:forEach var="member" items="${membersList}">
			<tr align="center">
				<td>${member.id}</td>
				<td>${member.pwd}</td>
				<td>${member.name}</td>
				<td>${member.email}</td>
				<td>${member.joinDate}</td>
				<td><a
					href="${contextPath}/member/removeMember.do?id=${member.id }">삭제하기</a></td>
			</tr>
		</c:forEach>
	</table>
	<a href="${contextPath}/member/memberForm.do"><h1
			style="text-align: center">회원가입</h1></a>
</body>
</html>

memberForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%   request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<style>
.text_center {
	text-align: center;
}
</style>
</head>
<body>
	<form method="post" action="${contextPath}/member/addMember.do">
		<h1 class="text_center">회원 가입창</h1>
		<table align="center">
			<tr>
				<td width="200"><p align="right">아이디</td>
				<td width="400"><input type="text" name="id"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">비밀번호</td>
				<td width="400"><input type="password" name="pwd"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이름</td>
				<td width="400"><p>
						<input type="text" name="name"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이메일</td>
				<td width="400"><p>
						<input type="text" name="email"></td>
			</tr>
			<tr>
				<td width="200"><p>&nbsp;</p></td>
				<td width="400"><input type="submit" value="가입하기"><input
					type="reset" value="다시입력"></td>
			</tr>
		</table>
	</form>
</body>

modMember.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<%  request.setCharacterEncoding("UTF-8"); %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 수정창</title>
<style>
.text_center {
	text-align: center;
}
</style>
</head>
<body>
	<form method="post" action="${contextPath}/member/modMember.do">
		<h1 class="text_center">회원 정보 수정창</h1>
		<table align="center">
			<tr>
				<td width="200"><p align="right">아이디</td>
				<td width="400"><input type="text" name="id"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">비밀번호</td>
				<td width="400"><input type="password" name="pwd"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이름</td>
				<td width="400"><p>
						<input type="text" name="name"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이메일</td>
				<td width="400"><p>
						<input type="text" name="email"></td>
			</tr>
			<tr>
				<td width="200"><p>&nbsp;</p></td>
				<td width="400"><input type="submit" value="수정하기"><input
					type="reset" value="다시입력"></td>
			</tr>
		</table>
	</form>
</body>
</html>

실행

http://localhost:8700/pro27/member/listMember.do 로 요청

안됨

http://localhost:8700/pro27/member/listMembers.do 로 요청

오류 잡겠다고 한시간은 돌아다닌거 같은데 결국은 오타였다..
스펠링을 잘보고! 오타를 내지말자!!


log4j

  • 로그 기능을 제공하는 오픈 소스 라이브러리
  • 애플리케이션에서 웹 사이트에 접속한 사용자 정보나 각 클래스의 메소드 호출 시각 등 여러 정보를 로그로 출력해서 관리
  • 메이븐에서는 프로젝트 생성 시 자동으로 log4j 라이브러리가 설치된다

log4j.xml 속 태그

  • <Appender>
    : 로그의 출력 위치를 결정(파일, 콘솔, DB 등)
    : log4j의 API 문서 속 XXXAppender로 끝나는 클래스 이름을 확인하면 출력 위치를 알 수 있다.
  • <Layout>
    : 어떤 형식으로 출력할 지 출력 레이아웃을 결정한다
  • <Logger>
    : 로깅 메시지를 Appender에 전달
    : 개발자가 로그 레벨을 이용해 로그 출력 여부를 조정한다
    : logger는 로그 레벨을 가지고 있으며, 로그의 출력 여부는 로그문의 레벨과 로거의 레벨을 가지고 결정

Appender 클래스

PatternLayout 클래스에서 사용되는 출력 속성

로그 레벨


log4j.xml을 이용해 로그 메시지 출력

log4j.xml 작성

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- ConsoleAppender를 이용해서 로그 메시지를 콘솔로 출력 -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<!-- PatternLayout의 출력형식 지정 -->
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>
	
	<!-- DailyRollingAppender를 이용해 로그 메시지를 파일로 출력 -->
	<appender name="dailyFileAppender" class="org.apache.log4j.DailyRollingFileAppender">
		<!-- 로그 파일의 생성 위치를 설정 -->
		<param name="File" value="C:\\spring\\logs\\output.log" />
		<param name="Append" value="true" />
		<!-- PatternLayout의 출력 형식 지정 -->
		<layout class="org.apache.log4j.PatternLayout">
			<param name="DatePattern" value="'.'yyyy-MM-dd" />
			<param name="ConversionPattern" value="[%d{HH:mm:ss}][%-5p](%F:%L)-%m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.myspring.pro27">
		<level value="info" />
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
	</logger>

	<logger name="org.springframework.web">
		<level value="info" />
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
	<root>
		<priority value="info" />
		<!-- 애플리케이션 전체 로그를 콘솔로 출력 -->
		<appender-ref ref="console" />
		<!-- 애플리케이션 전체 로그를 파일로 출력 -->
		<appender-ref ref="dailyFileAppender" />
	</root>
	
</log4j:configuration>

MemberControllerImpl.java 수정

...
@Controller("memberController")
public class MemberControllerImpl   implements MemberController {
	// LoggerFactory 클래스를 이용해 Logger 클래스 객체를 가져온다
	private static final Logger logger = LoggerFactory.getLogger(MemberControllerImpl.class);
	@Autowired
	private MemberService memberService;
	@Autowired
	private MemberVO memberVO ;
	
	@Override
	@RequestMapping(value="/member/listMembers.do" ,method = RequestMethod.GET)
	public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		
		// Logger 클래스의 info() 메소드로 로그 메시지 레벨을 info로 설정
		logger.info("viewName: "+ viewName);
		// Logger 클래스의 debug() 메소드로 로그 메시지 레벨을 debug로 설정
		logger.debug("viewName: "+ viewName);
		
		List membersList = memberService.listMembers();
		ModelAndView mav = new ModelAndView(viewName);
		mav.addObject("membersList", membersList);
		
		return mav;
	}
...

실행

적어준 위치 <param name="File" value="C:\\spring\\logs\\output.log" /> 에 로그 파일이 생성되었다


마이바티스 SQL문을 로그로 출력하려면

log4j.xml 수정
-> root logger 부분을 고쳐준다

	<!-- Root Logger -->
	<root>
		<priority value="debug" />
		<appender-ref ref="console" />
	</root>

실행

실행되는 SQL문과 SQL문 실행 후 반환되는 레코드가 출력되는 모습이 콘솔에 보인다

  • 전체 리스트 보기
  • 회원가입으로 insert 되는 모습 보기

AOP 용어 설명

지시자 종류

어드바이스 동작 시점

포인트컷 표현식


AOP를 이용한 로그 출력

pom.xml에 관련 라이브러리 설정 추가

...
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjtools</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>
...

root-context.xml에서 aop 설정 추가

파일 선택 후 하단에서 Namespaces 탭 선택 후 aop 항목 체크

소스 코드에 태그 추가

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
	
	<!-- aop 태그 추가 -->
	<aop:aspectj-autoproxy/>
</beans>

LogginAdvice.java

@Aspect 애너테이션 추가하기

package com.myspring.pro27;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogginAdvice {
	private static final Logger logger = LoggerFactory.getLogger(LogginAdvice.class);
	
	@Before("execution(* com.myspring.pro27.*.service.*.*(..)) or"
			+ "execution(* com.myspring.pro27.*.dao.*.*(..))")
	public void startLog(JoinPoint jp) {
		
		logger.info("-----------------------------------");
		logger.info("-----------------------------------");
		
		logger.info("1: " + Arrays.toString(jp.getArgs()));
		logger.info("2: " + jp.getKind());
		logger.info("3: " + jp.getSignature().getName());
		logger.info("4: " + jp.getTarget().toString());
		logger.info("5: " + jp.getThis().toString());
	}
	
	@After("execution(* com.myspring.pro27.*.service.*.*(..)) or"
			+ "execution(* com.myspring.pro27.*.dao.*.*(..))")
	public void after(JoinPoint jp) {
		
		logger.info("-----------------------------------");
		logger.info("-----------------------------------");
		
		logger.info("1: " + Arrays.toString(jp.getArgs()));
		logger.info("2: " + jp.getKind());
		logger.info("3: " + jp.getSignature().getName());
		logger.info("4: " + jp.getTarget().toString());
		logger.info("5: " + jp.getThis().toString());
	}
	
	@Around("execution(* com.myspring.pro27.*.service.*.*(..)) or"
			+ "execution(* com.myspring.pro27.*.dao.*.*(..))")
	public Object timeLog(ProceedingJoinPoint pjp) throws Throwable {
		long startTime = System.currentTimeMillis();
		logger.info(Arrays.toString(pjp.getArgs()));
		Object result = pjp.proceed();
		
		long endTime = System.currentTimeMillis();
		
		logger.info(pjp.getSignature().getName() + " : " + (endTime - startTime));
		logger.info("---------------------------------");
		
		return result;
	}
}

MemberController.java

@EnableAspectJAutoProxy 애너테이션 적용으로 aop 기능 활성화

@Controller("memberController")
@EnableAspectJAutoProxy
public class MemberControllerImpl   implements MemberController {
	// LoggerFactory 클래스를 이용해 Logger 클래스 객체를 가져온다
	private static final Logger logger = LoggerFactory.getLogger(MemberControllerImpl.class);
	@Autowired
    ...

실행

회원 조회 시 호출된 메소드에 대한 정보가 콘솔에 보인다


0개의 댓글

관련 채용 정보