20220916 [Spring Boot, Oracle, MyBatis]

Yeoonnii·2022년 9월 16일
1

TIL

목록 보기
28/52
post-thumbnail

Mybatis XML

새 프로젝트 생성

Oracle

회원 권한 생성

➡️ 권한 별로 테이블을 따로 만들어도 되고, 같은 테이블 안에서 권한을 추가로 줘도 된다

권한 생성시 null이 아님을 체크한 후 기본값을 주는 경우,

새로운 컬럼이 생성될 떄 기존에 존재하는 데이터는 값이 비어있으므로
null이 아닌 조건을 만족해야하니 기본값이 자동으로 체워진다

VSCODE

서버 구동시 터미널에서 오류, 출력결과확인 등 모든 정보를 확인해야 한다
환경적인 요소에서 문제가 발생했을 때 해당문제가 해결되지 않은 경우 서버가 실행되지 않는다

라이브러리추가

📁 pom.xml

<!-- oracle -->
	<dependency>
		<groupId>com.oracle.database.jdbc</groupId>
		<artifactId>ojdbc8</artifactId>
	</dependency>
        
<!-- mybatis -->
	<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>2.2.0</version>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>

환경설정

Application.java 실행시에 환경설정을 읽어들이는데
환경설정에 오류가 있다면 서버 구동이 안된다!
환경설정에 오류가 없어야 Controller, Mapper 등 다른 파일들이 실행된다

📁 templates/application.properties


# 서버주소
# 127.0.0.1:8080/BOOT1/
server.port=8080

# 나중에 프로젝트시 여러명 사용시에는 여러개 서버 생성해준다 
# server.servlet.context-path=/BOOT2
server.servlet.context-path=/BOOT1


# 소스코드 변경시 자동으로 서버 구동하기
spring.devtools.livereload.enabled=true


# view에 해당하는 html의 위치설정
# cache=false 개발시, 서비스 배포시에는 true
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# oracle
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@1.234.5.158:11521/xe
spring.datasource.username=ds207
spring.datasource.password=pw207

# mysql, mariadb
# spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
# spring.datasource.url=jdbc:mysql://localhost:3306/DB
# spring.datasource.username=아이디
# spring.datasource.password=암호


spring.datasource.hikari.connection-test-query=SELECT 1 FROM DUAL
spring.datasource.hikari.connection-timeout=600000
spring.datasource.hikari.maximum-pool-size=500
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.minimum-idle=20
spring.datasource.hikari.validation-timeout=3000
spring.datasource.hikari.idle-timeout=60000

config 파일 생성

memberMapper.xml 사용을 위해 memberMapper.xml가 위치한 mappers 폴더의 위치를 설정해주는 config 파일을 생성한다
➡️ config 파일은 사용자가 임의로 만든 폴더이므로 Application.java에 등록해줘야 한다

📃 로직
1. Service에서는 memberMapper.java를 사용하고
memberMapper.java에서는 쿼리문을 생략하여 작성한다
2. 생략된 쿼리문은 memberMapper.xml에 작성되어 있다
3. memberMapper.xml namespace로 작성된 쿼리문이 위치할 경로"com.example.mapper.MemberMapper"를 지정해준다

📁 MybatisConfig.java

  • 클래스명은 개발자 마음대로 생성하되, @로 역할을 명시해준다
    ➡️ @Configuration = 환경설정 파일
  • 원래 클래스는 메소드에 의해 호출되어야 실행되지만 @Bean이 붙으면 자동으로 서버 실행시 구동된다
    ➡️ @Bean = 객체 생성

    .getResources("classpath:/mappers/*Mapper.xml");

    • getResources = Resources를 가져온다
    • classpath = Resources를 의미한다
    • /mappers/ = mappers 폴더안의
    • *Mapper.xml = Mapper.xml 로 끝나는 모든 파일을 찾는다
@Configuration
@Slf4j
public class MybatisConfig {

    // @Bean =>객체 생성
    @Bean
	public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {        
		 // 서버구동시 이 부분 출력
         log.info("datasource configuration");
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource);
		
		// xml mappers 위치 설정  ex) resources폴더에 /mappers/memberMapper.xml
		Resource[] arrResource = new PathMatchingResourcePatternResolver().getResources("classpath:/mappers/*Mapper.xml");
		sqlSessionFactoryBean.setMapperLocations(arrResource);
		return sqlSessionFactoryBean.getObject();
	}
    
}

Application 설정(config, mapper)

  • 임의로 만든 config 파일을 application에 등록
  • mapper 사용 위한 파일 경로 지정

📁 Application.java

  • config 파일을 application에 등록
// 서비스,컨트롤러 환경설정
@ComponentScan(basePackages = {
	"com.example.service", 
	"com.example.controller",
	"com.example.config"
})
  • mapper 사용 위한 파일 경로 지정
// mybatis => mapper
// @MapperScan => mapper를 쓰기 위한 위치 지정
@MapperScan(basePackages = "com.example.mapper")

Mapper.xml 생성

  • namespacemapper.xml의 위치를 설정해준다
    = "com.example.mapper.MemberMapper”
  • 회원가입을 위한 쿼리문을 작성한다
    ➡️ parameterTypeMemberDTO로 설정하여 한번에 보낸다

📁 resources / mappers / memberMapper.xml

xml파일 작성시 첫번째 줄은 <?xml version ~ 으로 시작해야한다
첫번째 줄이 공백으로 시작할 경우 작동하지 않는다

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- 회원가입 -->
<mapper namespace="com.example.mapper.MemberMapper">
    <insert id="joinMember" parameterType="com.example.dto.MemberDTO">
    INSERT INTO MEMBERTBL(USERID, USERPW, AGE, PHONE, GENDER, REGDATE, ROLE)
    VALUES(#{userid}, #{userpw}, #{age}, #{phone}, #{gender}, CURRENT_DATE, #{role})
    </insert>
</mapper>

Mapper.java 생성

@Mapper를 지정해준다

  • MemberMapper.java 의
    인터페이스명 MemberMapper 과 메서드명 joinMember
    ➡️ memberMapper.xml 의
    namespace="com.example.mapper.MemberMapper, id="joinMember"와 일치해야 한다
  • MemberMapper.java의 인터페이스명과 memberMapper.xml의 namespace로 mapper를 검색하기 때문에 namespace는 고유해야 한다

📁 mapper / MemberMapper.java

@Mapper
public interface MemberMapper {

    // 여기를 생략했기 때문에 xml에서 찾아서 자동으로 수행한다
    public int joinMember( MemberDTO member );
    
}

DTO 생성

DB 입력시 데이터를 개별로 보낼수도 있지만, DTO를 이용하여 한번에 보내는게 효율적이다
➡️ 생성된 DTO는 Controller에서 사용

Oracle MEMBERTBL에 설정한 타입을 참고하여 생성
💡 join.htmlname값과 MemberDTO에 지정한변수명이 일치해야 데이터가 입력된다

📁 MemberDTO.java

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class MemberDTO {
    
    String userid;
    String userpw;
    int age;
    String phone;
    String gender;
    Date regdate;
    String role;

}

html 생성

Oracle MEMBERTBL을 참고하여 회원가입에 필요한 항목을 생성한다

  • input type이 사용자가 직접 입력하는 경우가 아닌 radiocheckbox같은 경우 DB에 저장할 값을 value를 지정하여 명시해준다
  • SUBMIT 제줄시 form안의 작업을 수행한다
    ➡️ form th:action="@{/member/joinaction.do}" method="post”

📁 join.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>회원가입</title>
</head>
<body>
    <h3>회원가입</h3>

    <form th:action="@{/member/joinaction.do}" method="post">
    <hr /><br />
    아이디 : <input type="text" name="userid" /><br />
    암호 : <input type="password" name="userpw"/><br />
    암호확인 : <input type="password" /><br /> 
    나이 : <input type="number" name="age"/><br />
    연락처 : <input type="text" name="phone"/><br />
    성별 : 
    <input type="radio" name="gender" value="M"/><input type="radio" name="gender" value="F"/><br />
    권한 : 
    <select name="role">
        <option value="CUSTOMER">고객</option>
        <option value="SELLER">판매자</option>
        <option value="ADMIN">운영자</option>
    </select>

    <hr /><br />
    <input type="submit" value="회원가입">
</form>
</body>
</html>

Controller (@PostMapping)

DB 전송 로직
1번이 정석! 지금은 실습이니 service 생략하고 2번으로 실행

  1. controller ⇒ service/serviceImpl ⇒ mapper + xml
  2. controller ⇒ mapper + xml

@PostMapping 작성하여 입력받은 값을 DB에 저장
@ModelAttribute 사용하여 MemberDTO로 데이터 전송

DB 전송 로직
@GetMapping에서 submit
@PostMapping(value = "/joinaction.do")로 이동
⇒ DB에 데이터 전송 완료 후 return "redirect:/home.do";

  • 출력시 {} 대괄호를 입력해야 전달값MemberDTO을 확인해 볼 수 있다
final String format = "Member => {} ";
  • 회원가입시 pw 암호화 안됨
    ➡️ MemberController.java에서 SecurityBCryptPasswordEncoder 이용하여
    암호 입력시 salt값 생성 + hashpw로 저장하도록 한다
    * BCryptPasswordEncoder 이용시 Security 내에서 salt값이 시스템 내에서 자동으로 생성된다
    ➡️ 회원가입시 같은 암호를 넣어도 hash값이 다르게 생성된다

📁 MemberController.java

@Controller
@RequestMapping(value = "/member")
@Slf4j
public class MemberController {
    @Autowired
    MemberMapper mMapper;

    // 출력용 포맷 ! 임의로 지정한 이름 Member
    final String format = "Member => {} ";

    // 회원가입 페이지로 이동
    // 127.0.0.1:8080/BOOT1/member/join.do
    @GetMapping(value = "/join.do")
    public String joinGET(){
        // resources/templates/member폴더생성/join파일생성
        return "member/join";
    }
    
    // 회원가입 DB전송
    @PostMapping(value = "/joinaction.do")
    public String joinPOST(@ModelAttribute MemberDTO member){
        // 잘 오는지 확인
        log.info(format, member.toString());

        // security 내에서 salt값 생성
        BCryptPasswordEncoder bcpe = new BCryptPasswordEncoder();
        String hashPW = bcpe.encode(member.getUserpw());
        member.setUserpw(hashPW);

        // DB처리
        // 회원가입 항목 6개를 한번에 받는다
        int ret = mMapper.joinMember(member);
        if(ret == 1) {
            // 수행후 적절한 페이지로 이동
            // http://127.0.0.1:8080/BOOT1/home.do
            return "redirect:/home.do";
        }
        return "redirect:/member/join.do";
    }

Spring Security

Spring을 사용할 때 애플리케이션에 대한 인증, 권한 부여 등의 보안 기능을 제공하는 프레임워크
➡️ 다양한 로그인 방법(Form, OAuth2, JWT 등...)에 대해 Spring이 일부를 구현했으니 이용시 수정(확장)하여 사용한다

주소 설정

홈 화면

GET => 127.0.0.1:8080/BOOT1/home.do

  • 회원가입
    GET => 127.0.0.1:8080/BOOT1/member/join.do
    POST => 127.0.0.1:8080/BOOT1/member/joinaction.do
  • 로그인
    GET => 127.0.0.1:8080/BOOT1/member/login.do

    권한별 홈 화면

    • 관리자 홈 화면
      GET => 127.0.0.1:9090/BOOT1/admin/home.do
    • 판매자 홈 화면
      GET => 127.0.0.1:9090/BOOT1/seller/home.do
    • 고객 홈 화면
      GET => 127.0.0.1:9090/BOOT1/customer/home.do

➡️ Security 이용하여 로그인 후 사용자의 권한에 해당하는 홈페이지만 접근이 가능하다

라이브러리 설치

📁 pom.xml

<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

설정하기

SecurityConfig.java에 환경설정하기

  1. 로그인 페이지 설정
  2. 로그아웃 설정
  3. 페이지별 접근권한 설정
  4. 접근 불가 페이지 설정
  5. 로그인시 비밀번호 hash로 변경

📁 SecurityConfig.java

➡️ Security 사용을 위해 생성
SecurityConfig가 Controller 역할까지 한다
로그인 페이지로 이동시 GET인 경우 화면 직접 생성, 로그인 처리하는 POST는 Security 사용

  • 로그인 페이지 설정시
    로그인 화면 GET MemberController에 생성, 로그인 처리 POST는 Security 사용

  • 로그아웃 페이지 설정시
    GET 사용 불가 , POST로 사용

    🤷‍♀️ 왜 로그아웃 시 POST를 사용해야 할까?
    👩‍🔧 로그아웃은 클라이언트에서 서버로 요청하는 것이니 GET, POST 중에서 선택해야 하는데,
    Get을 사용해도 동작하지 않는것은 아니지만 문제가 발생하는 경우가 있기 때문에 POST 사용이 권장된다
    💡 Spring Security 공식문서 참고

  • 페이지별 접근권한 설정
    로그인, 회원가입 페이지는 모든 권한이 접근 가능
    로그인 이후 획득한 권한별로 접근 가능한 곳 제한
    hasAnyAuthority이용하여 관리자는 판매자 홈페이지도 접근 가능하도록 설정

    • hasAuthority ➡️ 권한을 하나만 지정
    • hasAnyAuthority ➡️ 권한을 많이 지정할 수 있다! 목록 형태가 온다는 걸 알 수 있다
  • 접근 불가 페이지 설정
    로그인한 사용자의 권한이 접근하려는 페이지의 권한에 접근할수 없는 경우,
    접근불가 페이지로 이동하게 설정한다
    HomeController에서 생성
    ➡️ "/page403.do" = 127.0.0.1:8080/BOOT1/page403

📁 HomeController.java

@GetMapping(value = {"/page403"})
public String errorGet(){
    return "page403";
}

접근불가 페이지로 이동시 주소는 Controller에 명시된 주소로 이동하지만 accessDeniedPage("/page403.do")에 의해 page403의 화면이 나타난다

  • 로그인시 비밀번호 hash로 변경
    PasswordEncoder 이용하여 로그인시 비밀번호 hash로 변경 해준다
package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import com.example.service.CustomDetailsService;

@Configuration
@EnableWebSecurity

public class SecurityConfig{

    @Autowired
    CustomDetailsService customDetailsService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http)
        throws Exception {

            // 로그인 페이지 설정
            // 127.0.0.1:8080/BOOT1/member/login.do
            // <form th:action="@{/member/loginaction.do}" method="post">
            // <input type="text"  name="userid" />
            http.formLogin()
                .loginPage("/member/login.do")
                .loginProcessingUrl("/member/loginaction.do") //post로 가야될 주소
                .usernameParameter("userid")
                .passwordParameter("userpw")
                .defaultSuccessUrl("/home.do") //성공하면 home으로
                .permitAll();

            // 로그아웃 => GET불가 , POST 사용
            http.logout()
            .logoutUrl("/member/logoutaction.do")
            .logoutSuccessUrl("/home.do") //로그아웃 성공시 
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .permitAll();

            // 페이지별 접근권한 설정
            // 관리자권한은 판매자 페이지도 접근 가능하다
            http.authorizeRequests()
                // 관리자 페이지는 관리자권한만 접근가능하다
                .antMatchers("/admin", "/admin/**").hasAuthority("ADMIN") // hasAuthority
                // 판매자 페이지는 관리자권한과 판매자권한만 접근 가능하다
                .antMatchers("/seller", "/seller/**").hasAnyAuthority("ADMIN", "SELLER") 
                // 고객 페이지는 고객권한만 접근 가능하다
                .antMatchers("/customer", "/customer/**").hasAuthority("CUSTOMER")
                .anyRequest().permitAll();

            http.userDetailsService(customDetailsService);

            // 접근 불가 페이지 설정
            http.exceptionHandling().accessDeniedPage("/page403.do");

            return http.build();
        }

        // 로그인시 비밀번호 hash로 변경
        // 성공하면 홈으로 실패하면 그자리
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
}

📁 MemberController.java

로그인 생성

@GetMapping(value = "/login.do")
    public String loginGET() {
        return "member/login";
    }

📁 CustomDetailsService.java

Spring Security에서 유저의 정보를 불러오기 위해서 구현해야하는 인터페이스인 UserDetailsService를 상속받아 @Override를 작성한다
🌎 참고링크 : Spring Security UserDetails, UserDetailsService 란?

확인해보면 기본 오버라이드 메서드인 loadUserByUsername을 확인할 수 있다
loadUserByUsername = 유저의 정보를 불러와서 UserDetails로 리턴

  • 리턴타입으로 UserDetails를 갖는다
  • @param username 으로 어떤 user의 data인지 식별가능하다
  • @return은 null이 아닌 완전히 채워진 user record를 반환한다
    💡 오버라이드는 설계를 변경 할 수 없기 때문에 인터페이스에서 제공하는 형태에 맞추어 반환해야한다
    = 인터페이스 기준에 맞게 만들어 내야한다
    ➡️ 리턴 타입에 맞게 권한을 컬렉션 형태로 변환하고 리턴하는 권한자리에 넣어준다

public UserDetails loadUserByUsername(String username)

  • String타입의 username을 받으면 UserDetails를 반환
  • username은 변수 이름일 뿐, 사용자에게 입력받은 값을 Security가 내부적으로 처리해 username에 넣어준다
  • log.infousername확인하면 사용자의 id값인것을 알 수 있다

MemberDTO member = mMapper.selectMemberOne(username);
username(사용자의 id값)으로 MemberDTO에서 일치하는 회원의 아이디, 암호 정보 가져오기

반환시 UserDetails 타입의 User 메소드를 반환값으로 갖는다
➡️ UserDetailsService.userdetails.User; 또는 공식문서에서 확인할 수 있다

  • 권한은 컬렉션 타입으로 변경후에 넘겨야 한다

    🤷‍♀️권한도 string형이면 get으로 가져올 수 있는데 왜 컬렉션형일까?
    👩‍🔧 한 사람이 여러 권한을 가질수 있기 때문이다
    예를 들어, 한사람이 관리자 이면서, 사용자이면서, 판매자일수도 있다
    또 어떤 사람은 사용자 이면서 판매자 일 수도 있다
    위와 같은 경우 권한 여러개의 권한을 처리 하기 위해 컬렉션 형태를 사용한다

	String[] strRole = { member.getRole() }; 
	Collection<GrantedAuthority> role
		= AuthorityUtils.createAuthorityList(strRole);

return new User(아이디, 암호, 권한(=컬렉션타입)); ➡️ 반환되면 로그인처리 완료
리턴시 가져올 결과값을 mapper에서 짜준다 = userid가 오면 MemberDTO 반환

사용자 입력란이 빈칸인 경우는 백엔드에서 처리할 필요 없다
➡️ 프론트에서 유효성 검사하고 가져와야함

사용자가 입력한 데이터와 일치하는 회원정보가 없어서 로그인 처리가 안되는 경우 = null
➡️ 터미널 창에서 에러가 난것처럼 보인다

💡 if문 추가하여 회원정보가 null인 경우 와 null이 아닌경우 나누어 처리한다
= 터미널에 에러같이 출력되는것 방지하기위해 작성한 조건문

@Service
@Slf4j
// 시큐리티의 UserDetailsService를 상속받아 @Override를 작성
public class CustomDetailsService implements UserDetailsService{
    final String format = "SECURITY => {} ";

    @Autowired
    MemberMapper mMapper;

    @Override
    // String타입의 username을 받으면 UserDetails를 반환한다 
    // 아이디(username)가 전송되면 UserDetails 타입으로 변환하여 리턴
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  	// log.info로 username확인하면 사용자의 id인것을 알 수 있다
        log.info(format, username);

        // 전송된 아이디(username)으로 MemberDTO에서 아이디, 암호 가져오기
        MemberDTO member = mMapper.selectMemberOne(username);

        if(member != null){ // 입력된 member가 null이 아닌경우 = 회원정보가 있는경우
        // 권한 여러개 처리 위해 컬렉션형태 사용 = 권한을 컬렉션으로 변환해야한다
        String[] strRole = { member.getRole() }; 
        Collection<GrantedAuthority> role
            = AuthorityUtils.createAuthorityList(strRole);

        // 최종적인 리턴 타입은 User(아이디, 암호, 권한(=컬렉션타입))형태
        // return new User(아이디, 암호, 권한(=컬렉션타입)); => 반환되면 로그인처리 완료
        return new User(member.getUserid(), member.getUserpw(), role);
        }
        else { // 입력된 member 가 null인경우 = 회원정보가 없는경우
            String[] strRole = { "_" };
            Collection<GrantedAuthority> role = AuthorityUtils.createAuthorityList(strRole);

            // User(아이디, 암호, 권한(=컬렉션타입)           
            return new User(username, "", role);
        }
        // 빈칸인 경우는 프론트에서 유효성 검사, 백엔드에서 처리할 필요 없음
    }
}

📁 SecurityConfig.java

+ 추가

객체 가져오기

@Autowired
CustomDetailsService

가져온 객체 사용하기

 http.userDetailsService(customDetailsService);

📁 mapper/MemberMapper.java

mapper.java보고 mapper.xml만들 수 있어야 한다

📁 HomeController.java

홈 컨트롤러에서 로그인 여부를 확인하는 세션상태 출력
리턴값 User = UserDetails에서 반환된 User를 이용하여 로그인 성공/실패 출력

출력 결과는 터미널에서 확인이 가능하다

@Controller
public class HomeController {
    
// 크롬에서 127.0.0.1:8080/BOOT1
// 크롬에서 127.0.0.1:8080/BOOT1/
// 크롬에서 127.0.0.1:8080/BOOT1/home
// 크롬에서 127.0.0.1:8080/BOOT1/home.do
@GetMapping(value = {"/", "/home", "/home.do"})
public String homeGET(@AuthenticationPrincipal User user){ // UserDetails에서 반환된 User
    if( user == null ){
        System.out.println("로그인 실패");
    } else {
        System.out.println("로그인 성공");
    }
    return "home";
}

@GetMapping(value = {"/page403.do"})
public String page403Get(){
    return "page403";
}

}

📁 home.html

관리자 홈 http://127.0.0.1:8080/BOOT1/admin/home.do
판매자 홈 http://127.0.0.1:8080/BOOT1/seller/home.do
고객 홈 http://127.0.0.1:8080/BOOT1/customer/home.do

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>홈화면</title>
</head>
<body>
    <h3>홈화면</h3>

    <a th:href="@{/member/login.do}">로그인</a>
    <a th:href="@{/member/join.do}">회원가입</a>
    <form th:action="@{/member/logoutaction.do}" method="post">
        <input type="submit" value="로그아웃">
    </form>
    <hr />

    <a th:href="@{/admin/home.do}">관리자 홈</a>
    <a th:href="@{/seller/home.do}">판매자 홈</a>
    <a th:href="@{/customer/home.do}">고객 홈</a>

</body>
</html>

📁 page403.html

접근불가 페이지 생성 ➡️ home과 같은 파일에 생성해야한다

  <!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>접근불가페이지</title>
</head>
<body>
    접근불가 페이지 입니다

    <a th:href="@{/home.do}"><button>홈으로</button></a>
</body>
</html>

Controller(Admin/Customer/Seller)

📁 AdminController.java

@Controller
@RequestMapping(value="/admin")
public class AdminController {
    
    @GetMapping(value = "/home.do")
    public String homeGET(){
        return "admin/home";
    }
}

📁 CustomerController.java

@Controller
@RequestMapping(value="/customer")
public class CustomerController {
    @GetMapping(value = "/home.do")
    public String homeGET(){
        return "customer/home";
    } 
}

📁 SellerController.java

@Controller
@RequestMapping(value="/seller")
public class SellerController {
    @GetMapping(value = "/home.do")
    public String homeGET(){
        return "seller/home";
    } 
}

/home.html(Admin/Customer/Seller)

📁 admin/home.html

  <!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>관리자 홈화면</title>
</head>
<body>
    관리자 홈화면
</body>
</html>

📁 customer/home.html

  <!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>고객 홈화면</title>
</head>
<body>
    고객 홈화면
</body>
</html>

📁 seller/home.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>판매자 홈화면</title>
</head>
<body>
    판매자 홈화면
    
</body>
</html>

👨‍🏫 로그인, 로그아웃, 권한별 설정대로 접근이 가능한지만 확인/연습
추가적인 기능들은 추후에 배움
ex) 비 로그인 인 사용자가 판매자 페이지로 들어간 경우 로그인 창이 뜬다
로그인창에서 로그인 후 판매자 홈으로 바로 이동 가능하게끔 설정
⇒ 추가기능 설정하면 가능하다! 다음에 구현해볼것

0개의 댓글