본문 바로가기
웹 개발/수강신청 사이트 만들기

수강신청 사이트 보고서

by L3m0n S0ju 2022. 3. 26.

작성자: 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           엔티티 분석

 

그림 1-1

 

회원(User): 아이디, 패스워드, 이름, 학번, 역할(학생/교수) 정보가 저장된다. role을 통해 교수와 학생을 구분하도록 설계한다. 교수는 여러 개의 강의를 만들 수 있고 학생은 여러 개의 강의를 수강신청 할 수 있어야 하므로 UserLecture의 관계는 1:N이다. 교수님은 여러 개의 게시물을 작성할 수 있으므로 UserLecture의 관계는 1:N이다. 학생은 수강신청을 해야 하므로 Lecture와 다대다 관계가 되지 않기 위해서 중간에 SuGang 테이블을 추가해서 일대다 다대일로 풀어냈다.

 

강의(Lecture): 강의이름과 저장되고 user에는 강의를 만든 교수 정보가 저장된다. 강의마다 게시물을 여러 개 작성할 수 있으므로 LecturePost의 관계는 1:N이다.

 

게시물(Post): 게시물 제목, 내용, 글쓴이, 강의가 저장된다. 글쓴이는 게시물을 작성한 교수님의 정보가 저장되고 강의는 작성한 게시물의 강의 정보가 저장된다.

 

 

 

 

 

 

 

 

 


1.3     테이블 분석

 

그림 1-2

 

모두 1:N 관계인데 외래키는 모두 N에 설정했고 연관관계 매핑에서 연관관계 주인은 외래키가 있는 곳으로 정했다. LecturePost 사이 연관관계는 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 문제가 발생하지 않도록 하여 유지 보수가 쉽도록 설계했다. RoleEnumType으로 STUDENT, PROFESSOR 두 개의 문자열을 저장하여 학생과 교수의 신분을 구분하였다.

 

나머지 엔티티는 생략.

 

 

 

 

 

 

 

 

 

 

 


3              애플리케이션 구현 준비

 

3.1     애플리케이션 아키텍처

 

그림 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              애플리케이션 사이트

 

그림 5-1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

6              과제달성여부

 

6.1     [필수] 구현 - 로그인/회원 가입 10

  • 아이디/비밀번호로 회원 가입과 로그인이 가능해야 합니다.
  • 가입 시 입력받는 필수 정보는 아이디, 비밀번호, 이름, 학번, 교수자/학생 여부입니다.
  • 비밀번호는 저장할 때 원문을 복원할 수 없는 형태로 저장되어야 합니다.

 

 

그림 6-1

 그림 61과 같이 아이디/비밀번호로 로그인이 가능하고 비밀번호는 *로 출력된다.

 

 

 

 

 

 

 

 

그림 6-2

 

그림 6‑2와 같이 비밀번호는 DB에 원문을 복원할 수 없는 형태로 저장된다.

 

 

 

 

 

 

 

 

그림 6-3

그림 63과 같이 아이디, 비밀번호, 이름, 학번, 교수자/학생 여부를 입력 받고 만약 입력이 되지 않는 경우 빨간 테두리가 출력되며 회원 **은 필수입니다라는 문구가 출력된다.

 

 

 

 

 

 

 

 

 

 


6.2     [필수] 구현 - 교수자 - 강의 관리 10

  • 교수자 역할의 계정으로 새로운 강의를 등록할 수 있어야 합니다.
  • 교수자 역할의 계정으로 기존에 등록한 자신의 강의 목록을 조회할 수 있어야 합니다.

 

 

그림 6-4

 

그림 64와 같이 교수자 역할의 계정으로 새로운 강의를 등록할 수 있다.

 

 

 

          

 

 

 

그림 6-5

그림 65와 같이 기존에 등록한 자신의 강의 목록을 조회할 수 있다.

 

 

 

 

 

 

 

 

 


6.3     [필수] 구현 - 교수자 - 강의 게시물 작성 10

  • 교수자 역할의 계정으로 등록된 강의별로 게시물을 작성할수 있어야 합니다. 반드시 서식이 있는 텍스트(rich text)로 작성할 수 있어야 합니다.

 

 

그림 6-6

 

그림 65와 같이 교수자 역할의 계정으로 강의별로 게시물을 작성할 수 있다. 게시물 작성 폼으로 이동하면 그림 66과 같이 제목과 내용을 입력할 수 있는데 rich text css, js에서 문제가 발생했고 시간부족으로 인해 구현하지 않았다.

 

 

 

 

 

 

 

 

 

 


 

6.4     [필수] 구현 - 학생 - 강의 수강 신청 10

  • 학생 역할의 계정으로 존재하는 강의의 목록을 조회할 수 있어야 합니다.
  • 학생 역할의 계정으로 존재하는 강의를 수강신청할 수 있어야 합니다.

 

 

그림 6-7

 

학생의 계정으로 들어가면 학생 기능에 존재하는 강의의 목록을 조회하는 전체강의목록이 있다. 그리고 수강신청에서 존재하는 강의를 수강신청할 수 있다.

 

 

 

 

 

 

 

 

 

 

그림 6-8

그림 68과 같이 강의의 목록을 조회할 수 있다.

 

 

 

 

 

 

 

 

 

그림 6-9

그림 69와 같이 수강신청을 할 수 있다.

 

 

 

 

 

 

 


6.5     [필수] 구현 - 학생 - 강의 게시물 열람 10

  • 학생 역할의 계정으로 수강신청된 강의의 목록을 조회할 수 있어야 합니다.
  • 학생 역할의 계정으로 수강신청된 강의별 게시물 목록을 조회할 수 있어야 합니다.

 

그림 6-10

 

그림 610과 같이 학생 역할의 계정으로 수강신청된 강의의 목록을 조회할 수 있다.

 

 

 

 

 

 

 

 

그림 6-11

 

그림 610에서 코스명을 클릭하면 그림 611과 같이 해당 코스의 게시물을 열람할 수 있다. 따라서 강의별로 게시물 목록을 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

그림 6-12

게시물 제목을 클릭하면 해당 게시물을 열람할 수 있다.

 

 

 

 

 

 

 

 

 

 

 


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

 

댓글