전편에서 로그인을 구현했습니다.
회원이 되면, Role. 역할을 가지게 되는데요. 역할을 4개로 나눴습니다. 처음 가입하면 기본적으로 손님으로 되구요.
이번에 잘 알게되면 좋은 부분은, 뷰페이지에서 enum과 같은 데이터를 사용하는 방법 되겠습니다. 나머지의 부분들은, url의 연결, 기본적인 CRUD만들기. 이런부분이 되겠죠.
같이 공부해 봅시다.
세션은 로그인 후 생성되며, 로그아웃 후 삭제된다.
로그인을 하게 되면, 세션이 만들어지게 됨니다. 세션에 들어있는 사용자의 정보를 통해서, 보여주는 페이지를 다르게 할 수 있게 되죠. HttpSession에 기본적으로 저장되게 되며, 스프링부트 시큐리티에서, logout을 하면 자동적으로 만들어둔 세션을 지워줌니다.session.invalidate().
로그인 Oauth2 방식의 특징.
OAuth2 방식의 로그인은, application-oauth.properties 파일의 id와 비밀번호를 통해서... 구글의 경우 연결이 일어나게 만들 수 있습니다. 전편에서 했던 내용이죠. 또, application-oauth.properties파일은 gitignore파일로 만들어서, Github에 올라가지 않게 만들어야 겠죠.
구글 간편로그인의 경우, User 클래스. 사용자 클래스를 생성할 때에 기본적으로, Long형의 id, String형의 name, email, picture, Role형의 role을 갖게 됨니다.
Oauth2에서 User클래스.
스프링부트에서 User 클래스. 사용자 클래스에는 role형 칼럼이 붙게 되는데요. 사용자의 권한을 어디까지 하는가를 정할 수 있습니다. 사용자, 관리자. 이렇게 2개의 role이 있다면, ... 예를들어, 어느 url, /admin/data1/insert... 와 같이 url에 admin이 적혀있다면, 사용자의 경우는 해당 url의 접속이 되지 않게 만들 수 있죠.
그리고, 사용자 클래스에 칼럼을 더 추가할 수도 잇씁니다. 웹서비스의 속성에 따라서, 데이터 칼럼을 더 추가할 수도 있죠.
그렇다면, 이제 enum 클래스인 Role과, User클래스를 만들어 봅시다. 실제 Github에 올린 내용이므로, 참고만 하고 넘어가도 괜찮습니다. 다음에 서비스를 만들때에 참조하면 도움이 될거라고 생각해보네요.
Oauth2에서 Role과 User클래스의 예.
package org.example.domain.user;
@Getter
@RequiredArgsConstructor
public enum Role {
GUEST("ROLE_GUEST", "손님"),
USER("ROLE_USER", "일반 사용자"),
COMPANY("ROLE_COMPANY","기업 사용자"),
ADMIN("ROLE_ADMIN", "관리자");
private final String key;
private final String title;
}
그리고, User클래스. 회원가입하면 만들어지는, email, picture, name. 이 값을 가지는 엔티티에 각 Guest일때, User일때, Company일때, Admin일때. ... 각 Role을 엔티티로 가지고 있는 것이죠.
User 클래스는 이렇게 바뀜니다~.
package org.example.domain.user;
@Getter
@NoArgsConstructor
@Entity
public class User extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
@Column
private String picture;
@ManyToOne(targetEntity = RoleGUEST.class, fetch = FetchType.LAZY)
@JoinColumn(name = "ROLE_GUEST_ID")
private RoleGUEST roleGuest;
@ManyToOne(targetEntity = RoleUSER.class, fetch = FetchType.LAZY)
@JoinColumn(name = "ROLE_USER_ID")
private RoleUSER roleUser;
@ManyToOne(targetEntity = RoleCOMPANY.class, fetch = FetchType.LAZY)
@JoinColumn(name = "ROLE_COMPANY_ID")
private RoleCOMPANY roleCompany;
@ManyToOne(targetEntity = RoleADMIN.class, fetch = FetchType.LAZY)
@JoinColumn(name = "ROLE_ADMIN_ID")
private RoleADMIN roleAdmin;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
@Builder
public User(String name, String email, String picture, Role role) {
this.name = name;
this.email = email;
this.picture = picture;
this.role = role;
}
public User update(String name, String picture) {
this.name = name;
this.picture = picture;
return this;
}
public String getRoleKey() {
return this.role.getKey();
}
}
각 엔티티도 추가 되는 것이겠죠. 패키지, domain.roleclass.admin.RoleADMIN, RoleCOMPANY, RoleGUEST, RoleUSER 클래스를 각각 만들어 줌니다. 각각 admin, company, guest, user. 패키지를 따로 따로 만들어 줌니다. 여기 안에 또, 각각의 Service, Repository클래스들이 생길테니까요.
package org.example.domain.roleclass.admin;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity
@Table(name="ROLE_ADMIN")
public class RoleADMIN {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ROLE_ADMIN_ID")
private Long id;
}
위와 같은 형태로 만들면 되겠죠~.
일단 RoleCOMPANY부터 만들어 볼까요. 역할이 company일 경우, 기업이 되겠습니다. 전에 만든 Coperation클래스를 가지겠군요~.
Coperation 클래스.
package org.example.domain.coperation;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Getter
@Setter
@RequiredArgsConstructor
@SuperBuilder
@Table(name="T_COPERATION")
public class Coperation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "T_COPERATION_ID")
private Long id;
private String coperationName; //협력사명
private String catchPrice; //캐치프레이즈 예) 김치를 만들어보세요, 반조리음식. 이 일은 어떤가요.
private LocalDateTime crateDate; // 생성일
}
RoleCompany 클래스.
package org.example.domain.roleclass.company;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.example.domain.coperation.Coperation;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity
@Table(name="ROLE_COMPANY")
public class RoleCOMPANY {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ROLE_COMPANY_ID")
private Long id;
@ManyToOne(targetEntity = Coperation.class, fetch = FetchType.LAZY)
@JoinColumn(name = T_COPERATION_ID")
private Coperation coperation;
}
이제, RoleCompany의 Repository... 등등을 만듬니다. 실제 여기에 해당하는 클래스 코드들을 올리지는 않았습니다. 1편에 올렸구요. 그와 같은 내용이 되겠죠~. Github에 올라가 있군요.
그래서, 말하고 싶은 내용이라면... Oauth2에서, 회원의 정보. User클래스의 커스터마이징이 가능하고, 이 때에 잘 정해두어야 한다는 점. 서비스를 만들때 미리 생각해 두어야겠죠. 또, 어떤 서비스를 제공하는지에 따라, 데이터 로직을 만들어야 한다는 것과 그 로직을 만들때, Role은 생각을 할 중요한 분기점이 되고, 일반적으로 뷰 페이지의 변경. 사용자, 관리자. 이런 구분을 시키면서, 웹디자인, UI를 따로 만들어야 된다는 점이 되겠습니다.
로그인을 한 경우 네비게이션, ...
로그인을 한 경우, 기본적으로 이러한 네비게이션을 가짐니다. #네비게이션

처음에 로그인을 하게 되면, 사용자 권한, Role이 GUEST로 설정되게 됨니다. 그리고, 회원의 권한을 선택해주어야겠죠. 기본, 기업회원, 관리자.
사용자, 기업, 관리자의 공통의 페이지. 네비게이션 마이페이지의 편집~.
현재 Welcome페이지. 웹사이트를 처음 들어오면, 접속되는 컨트롤러에서의 url은, "/"입니다.
네비게이션인 마이페이지. 컨트롤러를 새로 만들어 줌니다. 메뉴마다, 컨트롤러 클래스를 만들면, 보기가 편하겠죠~.
MyPageController.java
사용할url은, /mypage/index 가 되겠습니다. 마찬가지로, 세션정보를 가져오구요.
userNameStr에는 회원의 id이름을 가져오고, userRoleStr에는 롤에따라서, 해당하는 이름들을 불러옴니다.
RequiredArgsConstructor
@Controller
public class MyPageController {
private final MemberService memberService;
private final WorkPlanService workPlanService;
private final WorkPlanRepository workPlanRepository;
private final CoperationService coperationService;
private final CoperationRepository coperationRepository;
private final HttpSession httpSession;
@GetMapping("/mypage/index")
public String mypageIndex(Model model){
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if(user!=null){
model.addAttribute("userNameStr", user.getName());
if (user.getRole().equals("GUEST")) {
model.addAttribute("userRoleStr", " 손님");
} else if (user.getRole().equals("USER")) {
model.addAttribute("userRoleStr", "일반회원");
} else if (user.getRole().equals("ADMIN")) {
model.addAttribute("userRoleStr", "관리자");
} else if (user.getRole().equals("COMPANY")) {
model.addAttribute("userRoleStr", "기업회원");
}
}
return "mypage/index";
}
}
마이페이지는 사용자와 기업. 관리자 모두 있는 페이지라고 합시다. 로그인 후 기능이죠.
url의 경우, mypage/index 로 하구요~. 어떤 문구가 어울릴지 생각해보아요.
안녕하세요. 반갑습니다. ㅇㅇㅇ 님~.
현재 해야할 역할을 지정해주세요.
1. 사용자 페이지 가기 2. 기업회원 페이지 가기 3.관리자 페이지 가기.
역할 바꾸기 버튼.
버튼을 누르면, 사용자의 Role정보를 바꿔줌니다.
타임리프에서 라디오 버튼 다루기. #타임리프 #라디오버튼
데이터를 잘 저장할 필요가 있습니다. 롤권한에 4가지 형태, GUEST, USER, COMPANY, ADMIN 되겠습니다.
enum을 하나 만들어 줌니다. 라디오버튼에 사용하고, 역할, Role과 관련이 있으니, 이름을 이렇게 지었습니다.
RoleRadioItemType.java ItemType라는 말은 데이터일 경우 달아주는 것으로 하구요.
package org.example.domain.form.mypage;
public enum RoleRadioItemType {
GUEST("손님"), USER("사용자"), COMPANY("기업회원"), ADMIN("관리자");
private final String description;
RoleRadioItemType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
위의 라디오버튼에 필요한, ItemType를 사용할 컨트롤러에 이렇게 메소드형식으로 넣어줌니다. 이렇게 하면, 이 메소드를 적은 컨트롤러 안에서 다 사용할 수 있게 됨니다.
@RequiredArgsConstructor
@Controller
public class MyPageController {
...
@ModelAttribute("roleRadioItemTypes")
public RoleRadioItemType[] roleItemTypes() {
return RoleRadioItemType.values();
}
}
그다음에는, 폼태그가 있으므로, 해당 데이터 빈 객체를 마이페이지를 넘겨줄때... 해당 페이지에 진입할때 빈 값을 하나 넘겨줘야 합니다.
MyController.java, 마이페이지에 갈때...
model.addAttribute("roleRadioForm", new RoleRadioForm());
@GetMapping("/mypage/index")
public String mypageIndex(Model model){
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if(user!=null){
model.addAttribute("userNameStr", user.getName());
if (user.getRole().equals("GUEST")) {
model.addAttribute("userRoleStr", " 손님");
} else if (user.getRole().equals("USER")) {
model.addAttribute("userRoleStr", "일반회원");
} else if (user.getRole().equals("ADMIN")) {
model.addAttribute("userRoleStr", "관리자");
} else if (user.getRole().equals("COMPANY")) {
model.addAttribute("userRoleStr", "기업회원");
}
}
model.addAttribute("roleRadioForm", new RoleRadioForm());
return "mypage/index";
}
실제, 해당 클래스도 만들어주고요. 폼태그 안에서 값을 넘겨주는 데이터, 파라메터 역할을 하게 되겠죠. 폼에 싣는 th:object에 해당하는 폼파라메터 클래스 객체. 또, 실제 enum으로 배열이 담겨있는 ItemType객체. 쌍으로해서, 패키지에 저장하면, 다음에 재사용성도 좋겠죠~.
Form으로 끝나는 클래스는 th:object, 값을 실을때에 쓰고, ItemType로 끝나면, enum 배열을 담는 객체로 쓰기로 하구요.
RoleRadioForm 클래스,
RoleRadkoItemType 클래스(enum)
package org.example.domain.form.mypage;
import lombok.Data;
@Data
public class RoleRadioForm {
String roleRadioItemType;
}
다 되었다면, 라디오 버튼을 만들어 둠니다. #컨테이너내부 #container
/resources/templates/mypage/index.html
<div class="container">
<!-- <h5> A 푸드. 음식. 김치를 만들어보세요.</h5>-->
<br />
<br/>
<h5>안녕하세요. 반갑습니다. <span th:text="${userNameStr}"></span> 님.</h5>
<hr/>
<p><span th:text="${userRoleStr}"></span> (으)로 로그인되어 있습니다.</p>
<hr/>
<div>
<div>회원 역할 변경하기</div>
<form action="/mypage/changeRole" th:object="${roleRadioForm}" method="post">
<div th:each="type : ${roleRadioItemTypes}" class="form-check form-check-inline">
<input type="radio" th:field="*{roleRadioItemType}" th:value="${type.name()}" class="form-check-input">
<label th:for="${#ids.prev('roleRadioItemType')}" th:text="${type.description}" class="form-check-label">
GUEST
</label>
</div>
<button type="submit" class="btn btn-primary">변경하기</button>
</form>
</div>
</div>
위의 코드를 보면, 폼태그의 object가 roleRadioForm입니다. th:value값에 type.name()의 값은, enum ItemType클래스의 이름을 가리킴니다. GUEST, USER, COMPANY, ADMIN이 되겠죠. type.description의 경우, enum, ItemType클래스에서 만들어 주었던 String description이 되겠죠.
마이페이지의 구현.

위와 같은 형태로, 마이페이지가 구현되었습니다. 폼태그의 변경하기 버튼이 눌린다면, 실제 어떤 역할로 바꿨는지 다시 바로 나오겠죠~. 변경하기 버튼을 누를때마다, 상태값이 출력되는 것을 볼 수 있습니다. 이제는, 사용자의 역할을 업데이트해주면 되겠죠~.

그리고, 변경된 role을 User 클래스에 반영해주고, 세션에 role값을 변경해서 저장해주고요~. url, /mypage/changeRole. 컨트롤러 메소드를 확장해서 적어줌니다.
세션을 불러오기. -> 유저 정보를 테이블에서 가져오기. -> role을 가져온 role로 바꾸기 -> 테이블을 저장 -> 세션도 변경된 값으로 저장.
@PostMapping("/mypage/changeRole")
public String indexDefault(Model model, RoleRadioForm role){
System.out.println("Role::::: " + role.getRoleRadioItemType()); // cmd 창에 출력, Role::::: COMPANY
//저장되어 있는 세션의 user 정보를 가져옴
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if(user!=null) {
//세션의 email로 유저정보를 불러오고, 그 유저의 role을 변경
String userEmail = user.getEmail();
User userBase = userService.findByEmail(userEmail);
if (role.getRoleRadioItemType().equals("GUEST")) {
userBase.setRole(Role.GUEST);
userService.save(userBase);
} else if (role.getRoleRadioItemType().equals("USER")) {
userBase.setRole(Role.USER);
userService.save(userBase);
} else if (role.getRoleRadioItemType().equals("COMPANY")) {
userBase.setRole(Role.COMPANY);
userService.save(userBase);
} else if (role.getRoleRadioItemType().equals("ADMIN")) {
userBase.setRole(Role.ADMIN);
userService.save(userBase);
}
//저장되어 있는 세션의 user의 role을 변경
user.setRole(role.getRoleRadioItemType());
//세션에 롤을 변경해서 다시 저장.
httpSession.setAttribute("user", new SessionUser(userBase));
user = (SessionUser) httpSession.getAttribute("user");
model.addAttribute("userNameStr", user.getName());
if (user.getRole().equals("GUEST")) {
model.addAttribute("userRoleStr", " 손님");
} else if (user.getRole().equals("USER")) {
model.addAttribute("userRoleStr", "사용자");
} else if (user.getRole().equals("ADMIN")) {
model.addAttribute("userRoleStr", "관리자");
} else if (user.getRole().equals("COMPANY")) {
model.addAttribute("userRoleStr", "기업회원");
}
}else{
//세션이 null인 경우, 기본 index페이지로 이동
return "index_log_leaf";
}
model.addAttribute("roleRadioForm", new RoleRadioForm());
return "mypage/index";
}
복잡하게 생각되기도 할 수있지만, 세션의 원리. 데이터의 CRUD에 익숙해지면 할 수 있을거라고 생각하네요. 익숙해지면 됨니다~.
웹 프로그래밍을 이렇게 하고 있습니다~.
로그인 구현 후,
세션의 구현.
User 클래스 다루기. 제공하는 서비스에 따라 데이터를 변경해주어야하고...
Role역할 디자인이 필요. 관리자, 사용자의 경우. ... 실제 롤 역할이 변경되는 경우의 웹 프로그래밍에 대해 생각해봐야 하구요~.
Role역할에 따라, 네비게이션, 마이페이지의 기본적인 구현. ... 여기까지 웹 프로그래밍을 해봤습니다~.
기술적으로는 폼태그, 타임리프에서 enum 클래스를 사용해서, 데이터 배열다루기. Radio버튼이였죠. 이 부분을 배웠습니다.
이 다음에는, 롤 역할 변경이 될때에, 네비게이션에 표시를 다르게 하는 부분. 또, Role이 Company인 경우. ... 기본적으로 어떻게 표시해야하는지 다뤄볼게요. 게시판의 CRUD라고 하죠. 그렇게 만들예정입니다.
여기까지 적어보네요.
지금 내용은 Github에 올렸습니다.
https://github.com/infott2t/ex05-springboot-querydsl
GitHub - infott2t/ex05-springboot-querydsl
Contribute to infott2t/ex05-springboot-querydsl development by creating an account on GitHub.
github.com
공부해보세요~. 재미있네요. 도움이 되었으면 좋겠습니다.
좋은 하루되세요.
--
저의 글, 봐 주셔서 감사합니다.
'프로그래밍' 카테고리의 다른 글
[웹앱 디자인] 스프링부트JPA 6. 개발 방식- 앱화면 기초, 템플릿 만들기. (0) | 2023.01.08 |
---|---|
[웹 프로그래밍] 스프링부트JPA 5. 회원 기본정보 확장하기. 연락처와 주소. (2) | 2023.01.07 |
[웹 프로그래밍] 스프링부트JPA 3. 스프링 시큐리티와 OAuth2.0. 간편로그인 구현하기. (2) | 2023.01.04 |
[웹 프로그래밍] 스프링부트JPA 2. 엔티티 심화. 맵핑하고, 타임리프 each문 작성해서 리스트 출력하기. (2) | 2023.01.02 |
[웹 프로그래밍] 스프링부트JPA 1. 데이터를 클래스화 하기. 자동 생성. (2) | 2023.01.01 |