- 본 강의의 전체 소스 공유 링크 : 진행중 오류가 있을 경우 소스 참조 바람
https://drive.google.com/file/d/1Ckb4GzmLek6A-J46dmibCt4Y2G3kckiV/view?usp=share_link
1) "Package Explorer" View 위에서 우측버튼 "New > Spring Starter Project" 선택
2) 생성할 Project 정보 입력
3) Spring Starter Dependency 추가
4) 생성된 Project의 구조
5) pom.xml에 JSP 지원을 위한 Dependency 추가
<!-- JSP 404 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>springbootweb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootweb</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JSP 404 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.demo.auth.UserVO" %>
<html>
<body>
<h2>Hello World~~!!!</h2>
<h2>This is helloJSP.jsp for Springboot project!!!</h2>
<%
out.println("This message is passed through HelloController~~~!!!");
%>
<br/>
<br/><br/>
<a href="/loginPage.do">로그인 페이지로 이동</a>
<br/><br/>
<a href="/soccer/players">선수 목록 조회 (로그인을 안하면 현재페이지로 Redirect 됨)</a>
<br/><br/>
<%
UserVO loginUser = (UserVO)session.getAttribute("LoginUser");
if( loginUser == null ){
out.println("선수목록 조회는 로그인을 하고 시도해 주세요.");
}
%>
</body>
</html>
package com.demo;
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;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class HelloController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@RequestMapping(value = "/", method = RequestMethod.GET)
public String goMain(Model model) {
log.debug("HelloController.goMain() invoked.");
return "helloJSP";
}
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String helloGetMethod(Model model) {
log.debug("HelloController.helloGetMethod() invoked.");
return "helloJSP";
}
@RequestMapping(value = "/hello", method = RequestMethod.POST)
public String helloPostMethod(Model model) {
log.info("HelloController.helloPostMethod() invoked.");
return "helloJSP";
}
}
package com.demo.auth;
import java.io.Serializable;
public class UserVO implements Serializable {
private static final long serialVersionUID = 1L;
private String userId;
private String passWd;
private String userName;
private int userLevel;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassWd() {
return passWd;
}
public void setPassWd(String passWd) {
this.passWd = passWd;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserLevel() {
return userLevel;
}
public void setUserLevel(int userLevel) {
this.userLevel = userLevel;
}
}
# Web JSP 설정
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
# DB 설정
spring.datasource.username=test_user
spring.datasource.password=testpw
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/TEST_DB?useUniCode=yes&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# MyBatis 설정
mybatis.type-aliases-package=com.demo.mapper
mybatis.mapper-locations=static/sqlmap/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
# 로깅 설정
logging.file.name=C:/BTC_JAVA/LOG/springbootweb.log
# 로그 파일 삭제 주기 (7일 이후 로그 삭제)
logging.file.max-history=7
# 로그 파일 하나당 최대 파일 사이즈
logging.file.max-size=10MB
# package 별로 로깅 레벨을 지정
logging.level.root=info
logging.level.com.demo=debug
1) Springboot Dashboard를 이용하여 Springboot 프로젝트 실행
2) 프로젝트 실행 로그 확인 : 자동 설정된 Logger에 의해 로그의 시간, Log Level, 로그를 남기는 Class명, 로그가 표시됨
3) http://localhost:8080 호출 테스트
<?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">
<!-- SQL Mapping -->
<mapper namespace="com.demo.mapper.AuthMapper">
<select id="getUserInfo" parameterType="com.demo.auth.UserVO" resultType="com.demo.auth.UserVO">
SELECT userid, username, userlevel
FROM user_mng
WHERE userid = #{userId} and passwd = #{passWd}
</select>
</mapper>
package com.demo.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.demo.auth.UserVO;
@Repository
@Mapper
public interface AuthMapper {
public UserVO getUserInfo(UserVO userVo);
}
package com.demo.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.mapper.AuthMapper;
@Service("authService")
public class AuthServiceImpl {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
AuthMapper authMapper;
public UserVO checkAuth(UserVO userVo) {
UserVO userResult = authMapper.getUserInfo(userVo);
return userResult;
}
}
package com.demo.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
@Controller
public class AuthController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
AuthServiceImpl authService;
@RequestMapping(value = "/loginPage.do", method = RequestMethod.GET)
public String goLoginPage(HttpServletRequest request, Model model) {
log.debug("LoginController.goLoginPage() invoked.");
String returnPage = "/auth/login";
// Session에 UserVO가 존재하면(이미 로그인됨) loginResult 페이지로 이동
HttpSession session = request.getSession();
UserVO loginUser = (UserVO) session.getAttribute("LoginUser");
if (loginUser != null) {
returnPage = "/auth/loginResult";
}
return returnPage;
}
// JSP의 input name들이 UserVO의 Member 변수와 같은 경우 UserVO에 Mappging되어 Parameter로 전달됨
@RequestMapping(value = "/auth/login.do", method = RequestMethod.POST)
public String loginFromDB(HttpServletRequest request, Model model, UserVO user) {
log.debug("LoginController.login() invoked. userId =[" + user.getUserId() + "] passwd =[" + user.getPassWd()
+ "]");
String returnPage = "/auth/login";
UserVO userResult = authService.checkAuth(user);
HttpSession session = request.getSession();
// 로그인 계정과 비번이 일치하면 User Level이 '0'이 아닌값이 Setting 됨
if (userResult != null && userResult.getUserLevel() != 0) {
System.out.println("Login Success~~~!!!!");
// JSP 화면에 서버의 처리값 전달 예시
log.debug("User ID =[" + userResult.getUserId() + "] Level = [" + userResult.getUserLevel() + "]");
// Session 처리
session.setAttribute("LoginUser", userResult);
returnPage = "/auth/loginResult";
} else {
System.out.println("Login Fail~~~ ㅠㅠ;");
userResult = new UserVO();
userResult.setUserLevel(-1);
// Session 삭제
session.setAttribute("LoginUser", null);
}
model.addAttribute("userResult", userResult);
return returnPage;
}
@RequestMapping(value = "/auth/logout.do", method = RequestMethod.GET)
public String logout(HttpServletRequest request) {
log.debug("LoginController.logout() invoked.");
HttpSession session = request.getSession();
session.setAttribute("LoginUser", null);
return "/auth/login";
}
}
package com.demo.common.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.demo.auth.UserVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
// 본 클래스는 Login Session을 처리하는 Interceptor 임
public class LoginInterceptor implements HandlerInterceptor {
private Logger log = LoggerFactory.getLogger(this.getClass());
// Controller로 호출 전 실행됨
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.debug("<LoginInterceptor> ======================= Started =======================");
HttpSession session = request.getSession();
UserVO loginUser = (UserVO) session.getAttribute("LoginUser");
// Login Session 정보가 없는 경우 index.jsp(/)로 Redirect 시킴
if (loginUser == null) {
log.debug("Unauthorized User........ㅠㅠ;");
response.sendRedirect("/");
return false;
}
return true;
}
// Controller가 모두 처리된 후 실행됨
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.debug("<LoginInterceptor> ======================= Finished =======================");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
// 사용자에게 Response된 이후에 실행됨
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.debug("LoginInterceptor.afterCompletion() invoked.....");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
package com.demo.common.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.demo.common.interceptor.LoginInterceptor;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// LoginInterceptor에서 Session을 점검할 Path를 설정하여 registry에 추가
List<String> interceptorPath = new ArrayList<String>();
interceptorPath.add("/auth/checkSession*");
interceptorPath.add("/soccer/**");
registry.addInterceptor(new LoginInterceptor()).addPathPatterns(interceptorPath).excludePathPatterns("/css/**",
"/images/**", "/js/**");
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.demo.auth.UserVO" %>
<html>
<body>
<h2>로그인 페이지</h2>
<br/><br/>
<form method="POST" action="/auth/login.do">
Login ID : <input type="text" name="userId" /><br/>
Password : <input type="text" name="passWd" />
<input type="submit" value="로그인"/>
</form>
<%
UserVO userResult = (UserVO)request.getAttribute("userResult");
if( userResult != null){
if( -1 == userResult.getUserLevel() ){
out.println("인증에 실패했습니다.");
}
}
%>
<br/><br/>
<a href="/">메인 페이지로 이동</a>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.demo.auth.UserVO" %>
<%!int userLevel;%>
<html>
<body>
<h2>로그인 결과 페이지</h2><br/>
<h2>Session Data</h2>
사용자 ID : ${LoginUser.userId} <br/><br/>
사용자 Level : ${LoginUser.userLevel} <br/><br/>
<br/><br/>
<a href="/soccer/players">선수 목록 조회(RESTfull 방식 - JSON 타입 Response)</a>
<br/><br/>
<a href="/soccer/players/1">1번 선수 조회(RESTfull 방식 - JSON 타입 Response)</a>
<br/><br/><br/>
<a href="/">메인 페이지로 이동</a>
<br/><br/>
<a href="/auth/logout.do">Logout</a>
</body>
</html>
- 참고) 선수 목록 조회 등 선수 관련 Service 링크는 현재 동작 안함
1) springbootweb을 Boot Dashboard에서 실행
2) http://localhost8080 으로 접속
3) "로그인 페이지로 이동" 링크를 클릭
4) 로그인 결과 페이지가 표시됨
5) "메인 페이지로 이동"을 클릭
6) "로그인 페이지로 이동"을 클릭
package com.demo.soccer;
public class SoccerPlayer {
int pId;
String pName;
String pPosition;
int height;
public int getpId() {
return pId;
}
public void setpId(int pId) {
this.pId = pId;
}
public String getpName() {
return pName;
}
public void setpName(String pName) {
this.pName = pName;
}
public String getpPosition() {
return pPosition;
}
public void setpPosition(String pPosition) {
this.pPosition = pPosition;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
<?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">
<!-- SQL Mapping -->
<mapper namespace="com.demo.mapper.SoccerPlayerMapper">
<select id="getPlayerList" resultType="com.demo.soccer.SoccerPlayer">
SELECT p_id, p_name, p_position, height
FROM PLAYER
</select>
<select id="getPlayer" parameterType="int" resultType="com.demo.soccer.SoccerPlayer">
SELECT p_id, p_name, p_position, height
FROM PLAYER
WHERE p_id = #{pId}
</select>
</mapper>
package com.demo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.demo.soccer.SoccerPlayer;
@Repository
@Mapper
public interface SoccerPlayerMapper {
public List<SoccerPlayer> getPlayerList();
public SoccerPlayer getPlayer(int pId);
}
package com.demo.soccer;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.mapper.SoccerPlayerMapper;
@Service
public class SoccerPlayerServiceImpl {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
SoccerPlayerMapper soccerPlayerMapper;
public List<SoccerPlayer> getSoccerPlayers() {
List<SoccerPlayer> playerList = soccerPlayerMapper.getPlayerList();
log.debug("Player List size = [" + playerList.size() + "]");
return playerList;
}
public SoccerPlayer getPlayer(int pId) {
SoccerPlayer player = soccerPlayerMapper.getPlayer(pId);
log.debug("Player = [" + player + "]");
return player;
}
}
package com.demo.soccer;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@Slf4j
// RestController로 설정하면 조회된 Object를 return 할 경우 JSON 타입으로 Response 됨
@RestController
public class SoccerPlayerController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
SoccerPlayerServiceImpl soccerPlayerService;
@RequestMapping(value = "/soccer/players", method = RequestMethod.GET)
public List<SoccerPlayer> getSoccerPlayers(Model model) {
log.debug("SoccerPlayerController.getSoccerPlayers() invoked.");
List<SoccerPlayer> soccerPlayers = soccerPlayerService.getSoccerPlayers();
return soccerPlayers;
}
@RequestMapping(value = "/soccer/players/{playerId}", method = RequestMethod.GET)
public SoccerPlayer getSoccerPlayer(Model model, @PathVariable("playerId") Integer playerId) {
log.debug("SoccerPlayerController.getSoccerPlayer() invoked. playerId = [" + playerId + "]");
SoccerPlayer soccerPlayer = soccerPlayerService.getPlayer(playerId);
return soccerPlayer;
}
}
1) Springboot Dashboard를 이용하여 Springboot 프로젝트 실행
2) http://localhost:8080 호출 테스트
3) "선수 목록 조회 (로그인을 안하면 현재페이지로 Redirect 됨)" 링크를 클릭해도 현재는 로그인이 안되어 있기 때문에 "/"로 Redirect 되어 메인페이지가 표시됨
4) "로그인 페이지로 이동" 링크를 클릭하여 user / 1234를 입력후 로그인
5) "선수 목록 조회(RESTfull 방식 - JSON 타입 Response)" 링크를 클릭
6) "1번 선수 조회(RESTfull 방식 - JSON 타입 Response)" 링크 클릭
7) 현재 로그인된 상태에서 메인 페이지로 이동하여 "선수 목록 조회 (로그인을 안하면 현재페이지로 Redirect 됨)" 링크를 클릭
Springboot를 이용하여 JSP 화면을 이용하는 것과 RESTful 방식의 API 서비스를 개발하는 방법 모두를 하나의 프로젝트에서 구현해 보았습니다.
여기까지 Springboot 강의를 마치겠습니다.^^
Java 개발자들은 Springboot로 봄이 찾아 왔지만
IT 기술이 많이 발전하고 있어서 개발자는 항상 게으르지 말고 열심히,
또 즐겁게 공부를 하기 바랍니다~
2023년도에도 이제 봄이 찾아왔습니다... ^^
진해 군항제 보고 싶네요.