organize/프로젝트

justBoard4 화면(view)1

001cloudid 2024. 9. 23. 16:51
728x90

화면 구성 main에서 회원가입을 클릭하면 Get 방식으로 회원가입 페이지로 이동 → 아이디, 비밀번호, 비밀번호 재확인, 이름을 입력 받고 회원가입 버튼을 클릭하면 회원가입이 가능하게 하기 회원가입 과정은 Post 방식을 이용

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<body>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post">
아이디 : <input type="text" name="id" required="required"><br>
비밀번호 : <input type="password" name="pw" required="required"><br>
비밀번호 재확인 : <input type="password" name="pwre" required="required"><br>
이름 : <input type="text" name="name" required="required"><br>
<input type="submit" value="회원가입"> 
</form>
</body>
</html>

화면 구성이 너무 없어보임. input 태그가 정렬 안된 느낌.. 물론 화면이 주는 아니지만 기본적으로 그냥 예의가 없는 화면...

최소한 정보를 입력받는게 정렬되게 바꿔봄

input 태그에 placeholder로 각 항목에 제약사항을 넣어봤는데 짤리는 부분이 있음. 우리나라 최고의 포털사이트 중 하나인 네이버 회원가입을 살펴보면

네이버 회원가입
네이버 회원가입

따로 텍스트가 없고, placeholder를 사용하고, jQuery ajax를 이용한다는 것을 알 수 있음.

최대 포털에서 이렇게 사용한다는 것은 회원 가입을 원하는 이용자가 불편함을 느끼지 않는다는 뜻이라고 생각된다.

처음부터 저렇게 만들면 좋겠지만, 조금조금씩 추가하는 방향으로 하는게 과부하를 방지할 수 있을 것 같음

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.formstyle{
	width : 400px;
	
}
.label{
	width : 200px;
}
.validation{
	widows: 200px;
	height: 30px;
}
</style>
<body>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post">
<div class="formstyle">
<input type="text" name="id" required="required" placeholder="아이디"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" name="pwre" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입"> 
</form>
</body>
</html>

 

비밀번호 재확인에 name을 넣어줬는데, 이 정보는 DB에 저장하는 용도가 아닌 정보 확인용이기 때문에  해당 input 태그에 name이 필요없음 → 즉 <input type="password" required="required" placeholder="비밀번호재확인"><br>

 


프로젝트하면서는 전혀 신경쓰지 않았던 것 → 어노테이션, 언제쓰는지는 아는데 안에 어떻게 생긴건지 살펴 볼 시간이 없었음.

대표적으로 @Controller 어노테이션을 살펴보면

/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Indicates that an annotated class is a "Controller" (e.g. a web controller).
 *
 * <p>This annotation serves as a specialization of {@link Component @Component},
 * allowing for implementation classes to be autodetected through classpath scanning.
 * It is typically used in combination with annotated handler methods based on the
 * {@link org.springframework.web.bind.annotation.RequestMapping} annotation.
 *
 * @author Arjen Poutsma
 * @author Juergen Hoeller
 * @since 2.5
 * @see Component
 * @see org.springframework.web.bind.annotation.RequestMapping
 * @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any
	 */
	String value() default "";

}

@interface Controller{} 로 되어 있는 것을 알 수 있는데, 이는 커스텀 어노테이션을 정의하는 방법으로 정의되어있음

※ 커스텀 어노테이션 정의 @interface 어노테이션 이름

 

 

Controller 클래스

아키텍처에서 컨트롤러를 정의할 때 사용

  • @Controller MVC
    해당 클래스가 웹 애플리케이션의 컨트롤러임을 표시.  HTTP 요청을 처리하고 응답을 생성하는 역할을 담당
  • @Inject
    종속성 주입을 수행하는 데 사용. 클래스의 필드, 생성자, 메소드 등에 적용할 수 있음. 클래스에 필요한 종속성을 자동으로 주입할 수 있음

    public @interface Inject {}

  • @GetMapping
    HTTP Get 요청을 처리하는 메소드

    @RequestMapping(method = RequestMethod.GET)
    public @interface GetMapping {

    /**
     * Alias for {@link RequestMapping#name}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String name() default "";

    /**
     * Alias for {@link RequestMapping#value}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};

    /**
     * Alias for {@link RequestMapping#path}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] path() default {};

    /**
     * Alias for {@link RequestMapping#params}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] params() default {};

    /**
     * Alias for {@link RequestMapping#headers}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] headers() default {};

    /**
     * Alias for {@link RequestMapping#consumes}.
     * @since 4.3.5
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] consumes() default {};

    /**
     * Alias for {@link RequestMapping#produces}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] produces() default {};

  • PostMapping
    HTTP Post 요청을 처리하는 메소드

    @RequestMapping(method = RequestMethod.POST)
    public @interface PostMapping {

    /**
     * Alias for {@link RequestMapping#name}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String name() default "";

    /**
     * Alias for {@link RequestMapping#value}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};

    /**
     * Alias for {@link RequestMapping#path}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] path() default {};

    /**
     * Alias for {@link RequestMapping#params}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] params() default {};

    /**
     * Alias for {@link RequestMapping#headers}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] headers() default {};

    /**
     * Alias for {@link RequestMapping#consumes}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] consumes() default {};

    /**
     * Alias for {@link RequestMapping#produces}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] produces() default {};

  • @ResponseBody
    컨트롤러의 메소드에 적용되어 해당 메소드가 HTTP 응답의 본문을 직접 반환함. 메소드가 반환하는 객체가 HTTP 응답 본문에 직접 포함되어 클라이언트로 전송됨. 일반적으로 컨트롤러의 메소드가 String, JSON, XML 등의 데이터를 반환 할 때 사용

아무리 봐도 DI(의존성 주입)이란걸 정리해둔걸 한 줄로 요약이 되는데, 진짜 이해가 안됨. A가 B를 이용하면 A는 B에 의존한다? 그래서 검색도 해보고 유튜브 검색도 해봤음. 유튜브 5분개발지식님이 올려둔 의존성 주입 설명을 캡쳐해보았다.

출처 : 5분개발지식 - 의존성 주입 3분만에 이해하기

위의 그림을 본다고해도 이해되는 건 아닌데, 대략적으로 이러이러한 것이다 라고 이야기는 할 수 있지 않을까?

결론은 의존성 주입이라는게 너무 추상적이다... 계속하다보면 되겠지라는 생각으로 꾸준히 이해하려고 노력해보자

 

여담으로 나는 프로젝트를 진행할 때 큰 틀을 만들어 놓고 → 페이지 작업 → DB 작업(스키마, 테이블, 컬럼 만들기) → 클래스 작업으로 하는 것을 선호한다.

이유는 첫째는 페이지를 만들면서, 큰 틀에서 생각해둔 DB를 수정하고 클래스 작업(Controller - Service - DAO - Mapper)을 진행하는 것이 내 입장에서는 편함. 둘째 페이지를 만들면서 이런 기능을 넣으면 좋겠는데? 넣어보자하는게 생기기 때문에 클래스 작업하거나 자바스크립트 사용해 즉각적으로 할 수 있기 때문이다.

 

기본적으로 수요일까지 화면 구성을 끝 마치고 DB작업 후 클래스 작업하는 순서로 진행하고자한다.

 

 

 

만들어야하는 페이지(view)

  • member
    회원가입 -> 정규표현식을 이용해서 유효성검사, ajax를 이용하여 중복확인
    내 정보 → 정보 수정(이름, 비밀번호), 탈퇴
  • board
    게시판 리스트 + 글 조회
    글 쓰기(회원만)
    글 수정, 글 삭제(작성자만)

앞으로 4개의 페이지를 수요일 전까지 만들고 이어서 DB 수정하는 식으로 하자.

 

 

두 개의 차이 → 접근 제어자 왼쪽은 default, 오른쪽은 public 이 경우 패키지가 다를 경우 접근을 못해서 해당 객체를 사용하지 못 함.

728x90