작성자: Lemon_soju
github: https://github.com/Lemon-soju/University_Sugang_Site
개발환경
개발언어: Java
프레임워크: 스프링
IDE: IntelliJ IDEA Community Edition
데이터베이스: H2 1.4.200
1 도메인 분석 설계
1.1 요구사항 분석
1. [필수] 구현 - 로그인/회원 가입 10
아이디/비밀번호로 회원 가입과 로그인이 가능해야 합니다.
가입 시 입력받는 필수 정보는 아이디, 비밀번호, 이름, 학번, 교수자/학생 여부입니다.
비밀번호는 저장할 때 원문을 복원할 수 없는 형태로 저장되어야 합니다.
2. [필수] 구현 - 교수자 - 강의 관리 10
교수자 역할의 계정으로 새로운 강의를 등록할 수 있어야 합니다.
교수자 역할의 계정으로 기존에 등록한 자신의 강의 목록을 조회할 수 있어야 합니다.
3. [필수] 구현 - 교수자 - 강의 게시물 작성 10
교수자 역할의 계정으로 등록된 강의별로 게시물을 작성할수 있어야 합니다. 반드시 서식이 있는 텍스트(rich text)로 작성할 수 있어야 합니다.
4. [필수] 구현 - 학생 - 강의 수강 신청 10
학생 역할의 계정으로 존재하는 강의의 목록을 조회할 수 있어야 합니다.
학생 역할의 계정으로 존재하는 강의를 수강신청할 수 있어야 합니다.
5. [필수] 구현 - 학생 - 강의 게시물 열람 10
학생 역할의 계정으로 수강신청된 강의의 목록을 조회할 수 있어야 합니다.
학생 역할의 계정으로 수강신청된 강의별 게시물 목록을 조회할 수 있어야 합니다.
1.2 도메인 모델과 테이블 설계
1.2.1 엔티티 분석
회원(User): 아이디, 패스워드, 이름, 학번, 역할(학생/교수) 정보가 저장된다. role을 통해 교수와 학생을 구분하도록 설계한다. 교수는 여러 개의 강의를 만들 수 있고 학생은 여러 개의 강의를 수강신청 할 수 있어야 하므로 User와 Lecture의 관계는 1:N이다. 교수님은 여러 개의 게시물을 작성할 수 있으므로 User와 Lecture의 관계는 1:N이다. 학생은 수강신청을 해야 하므로 Lecture와 다대다 관계가 되지 않기 위해서 중간에 SuGang 테이블을 추가해서 일대다 다대일로 풀어냈다.
강의(Lecture): 강의이름과 저장되고 user에는 강의를 만든 교수 정보가 저장된다. 강의마다 게시물을 여러 개 작성할 수 있으므로 Lecture와 Post의 관계는 1:N이다.
게시물(Post): 게시물 제목, 내용, 글쓴이, 강의가 저장된다. 글쓴이는 게시물을 작성한 교수님의 정보가 저장되고 강의는 작성한 게시물의 강의 정보가 저장된다.
1.3 테이블 분석
모두 1:N 관계인데 외래키는 모두 N에 설정했고 연관관계 매핑에서 연관관계 주인은 외래키가 있는 곳으로 정했다. Lecture과 Post 사이 연관관계는 Post쪽에 외래키가 있으므로 Post를 연관관계 주인으로 설정했다.
2 엔티티 클래스 개발
@Entity
@Getter @Setter
public class User {
@Id
@GeneratedValue
@Column(name = "user_id")
private Long id;
private String uid;
private String pwd;
private String name;
private Long studentId;
@Enumerated(EnumType.STRING)
private Role role;
//== 연관관계 메서드 ==//
public void addLecture(Lecture lecture){
lecture.setUser(this);
}
}
모든 엔티티의 식별자는 id로 사 용하고 컬럼명은 소문자 클래스명 뒤에 _id를 붙이는 식으로 설정했다. @ManyToOne 관계는 모두 LAZY로 설정하여 N+1 문제가 발생하지 않도록 하여 유지 보수가 쉽도록 설계했다. Role은 EnumType으로 STUDENT, PROFESSOR 두 개의 문자열을 저장하여 학생과 교수의 신분을 구분하였다.
나머지 엔티티는 생략.
3 애플리케이션 구현 준비
3.1 애플리케이션 아키텍처
계층형 구조 사용
controller, web: 웹 계층
service: 비즈니스 로직, 트랜잭션 처리
repository: JPA를 직접 사용하는 계층, 엔티티 매니저 사용
domain: 엔티티가 모여 있는 계층, 모든 계층에서 사용
패키지 구조
lemonsoju_group.lemonsoju_artifact
domain
interceptor
repository
service
web
4 회원 도메인 개발
3가지 도메인 중에서 회원 도메인은 예시로 대략적인 기능을 설명하겠다.
구현 기능
회원 등록
로그인
로그아웃
순서
회원 리포지토리 개발
회원 서비스 개발
4.1 회원 리포지토리 개발
@Repository
@RequiredArgsConstructor
public class UserRepository {
private final EntityManager em;
public Long save(User user){
em.persist(user);
return user.getId();
}
public User findOne(Long id){
return em.find(User.class, id);
}
public Optional<User> findByUid(String uid){
return em.createQuery("select u from User u where u.uid = :uid", User.class)
.setParameter("uid", uid)
.getResultList()
.stream().findFirst();
}
public List<User> findAll(){
return em.createQuery("select u from User u", User.class)
.getResultList();
}
public List<User> findByName(String name){
return em.createQuery("select u from User u where u.name = :name", User.class)
.setParameter("name", name)
.getResultList();
}
}
기능
save -> 회원 저장
findOne -> 테이블 id를 통해 회원 찾기
findByUid -> 사용자 id를 통해 회원 찾기
findAll -> 모든 회원 찾기 -> 사용 X
findByName -> 이름으로 회원 찾기
기능 중에서는 사용하지 않는 기능도 있으나 이후 사용할 것 같아서 미리 만든 기능들이다.
4.2 회원 서비스 개발
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor // final이 붙은 클래스 자동으로 인젝션하여 생성자를 생성한다
@Slf4j
public class UserService {
private final UserRepository userRepository;
private final LectureRepository lectureRepository;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 회원 가입
*/
@Transactional
public Long join(User user) {
String encodePwd = passwordEncoder.encode(user.getPwd());
user.setPwd(encodePwd);
validateDuplicateUser(user);
userRepository.save(user);
return user.getId();
}
private void validateDuplicateUser(User user) {
Optional<User> findUsers = userRepository.findByUid(user.getUid());
if (!findUsers.isEmpty()) {
throw new IllegalStateException("Already Existing User");
}
}
/**
* 회원 전체 조회
*/
public List<User> findUsers(){
return userRepository.findAll();
}
public User findOne(Long userId){
return userRepository.findOne(userId);
}
}
기능
passwordEncoder -> 비밀번호 암호화를 위해 선언
join -> 회원가입 기능이다. Transactional을 설정해야 영속성 컨텍스트 문제가 발생하지 않는다.
validateDuplicateUser -> 같은 아이디의 유저가 있으면 예외를 발생시킨다.
findUsers -> 모든 사용자를 가져온다.
findOne -> 테이블 id를 통해 사용자 정보를 불러온다.
컨트롤러 기능은 생략하겠다.
5 웹 애플리케이션 사이트 맵
6 과제달성여부
6.1 [필수] 구현 - 로그인/회원 가입 10
- 아이디/비밀번호로 회원 가입과 로그인이 가능해야 합니다.
- 가입 시 입력받는 필수 정보는 아이디, 비밀번호, 이름, 학번, 교수자/학생 여부입니다.
- 비밀번호는 저장할 때 원문을 복원할 수 없는 형태로 저장되어야 합니다.
그림 6‑1과 같이 아이디/비밀번호로 로그인이 가능하고 비밀번호는 *로 출력된다.
그림 6‑2와 같이 비밀번호는 DB에 원문을 복원할 수 없는 형태로 저장된다.
그림 6‑3과 같이 아이디, 비밀번호, 이름, 학번, 교수자/학생 여부를 입력 받고 만약 입력이 되지 않는 경우 빨간 테두리가 출력되며 “회원 **은 필수입니다”라는 문구가 출력된다.
6.2 [필수] 구현 - 교수자 - 강의 관리 10
- 교수자 역할의 계정으로 새로운 강의를 등록할 수 있어야 합니다.
- 교수자 역할의 계정으로 기존에 등록한 자신의 강의 목록을 조회할 수 있어야 합니다.
그림 6‑4와 같이 교수자 역할의 계정으로 새로운 강의를 등록할 수 있다.
그림 6‑5와 같이 기존에 등록한 자신의 강의 목록을 조회할 수 있다.
6.3 [필수] 구현 - 교수자 - 강의 게시물 작성 10
- 교수자 역할의 계정으로 등록된 강의별로 게시물을 작성할수 있어야 합니다. 반드시 서식이 있는 텍스트(rich text)로 작성할 수 있어야 합니다.
그림 6‑5와 같이 교수자 역할의 계정으로 강의별로 게시물을 작성할 수 있다. 게시물 작성 폼으로 이동하면 그림 6‑6과 같이 제목과 내용을 입력할 수 있는데 rich text는 css, js에서 문제가 발생했고 시간부족으로 인해 구현하지 않았다.
6.4 [필수] 구현 - 학생 - 강의 수강 신청 10
- 학생 역할의 계정으로 존재하는 강의의 목록을 조회할 수 있어야 합니다.
- 학생 역할의 계정으로 존재하는 강의를 수강신청할 수 있어야 합니다.
학생의 계정으로 들어가면 학생 기능에 존재하는 강의의 목록을 조회하는 전체강의목록이 있다. 그리고 수강신청에서 존재하는 강의를 수강신청할 수 있다.
그림 6‑8과 같이 강의의 목록을 조회할 수 있다.
그림 6‑9와 같이 수강신청을 할 수 있다.
6.5 [필수] 구현 - 학생 - 강의 게시물 열람 10
- 학생 역할의 계정으로 수강신청된 강의의 목록을 조회할 수 있어야 합니다.
- 학생 역할의 계정으로 수강신청된 강의별 게시물 목록을 조회할 수 있어야 합니다.
그림 6‑10과 같이 학생 역할의 계정으로 수강신청된 강의의 목록을 조회할 수 있다.
그림 6‑10에서 코스명을 클릭하면 그림 6‑11과 같이 해당 코스의 게시물을 열람할 수 있다. 따라서 강의별로 게시물 목록을 확인할 수 있다.
게시물 제목을 클릭하면 해당 게시물을 열람할 수 있다.
7 (테스트)초기 데이터
교수1
-> id: lemon2
-> pwd: asd123
-> name: James
-> 학번: 2018613142
교수2
-> id: lemon3
-> pwd : asd123
-> name: Charlie
-> 학번: 2014326122
학생1
-> id: lemon
-> pwd: asd123
-> name: lemon_soju
-> 학번: 2017320162
강의1
-> 이름: JAVA Programming
-> 교수1
강의2
-> 이름: Advanced Hacking Practice
-> 교수1
강의3
-> 이름: PYTHON Programming
-> 교수2
수강신청
-> (학생1, 강의3)
-
강의게시물1
-> 제목: test01
-> 내용: Hello~ This course is Java Programming!!
-> 교수1
-> 강의1
강의게시물2
-> 제목: test02
-> 내용: Assignment is in Blackboard
-> 교수1
-> 강의1
강의게시물3
-> 제목: test03
-> 내용: This course is Advanced Hacking Practice
-> 교수1
-> 강의2
'웹 개발 > 수강신청 사이트 만들기' 카테고리의 다른 글
비밀번호 암호화 (0) | 2022.03.25 |
---|---|
교수, 학생 역할 구분 및 수강신청 기능 추가 (0) | 2022.03.23 |
강의등록, 게시물 등록 기능 추가 (0) | 2022.03.21 |
강의목록 열람 페이지 구현 (0) | 2022.03.14 |
로그인, 로그아웃, 회원가입, 세션 기능 추가 (0) | 2022.03.13 |
댓글