[Spring]

포키·2023년 6월 2일
0

국비과정

목록 보기
71/73

프레임워크와 라이브러리의 차이
프레임워크는 IoC(Inversion of Control)가 일어남 = 개발자가 정해진 규칙(사용 방식)을 따라감
라이브러리는 개발자가 사용하는 방식을 정해서 사용


Spring

  • 스프링 개발 방식은 레거시 or 스프링 부트
  • 4.1부터는 레거시 프로젝트 지원x, 스프링 부트 3.0부터 자바 고버전만 지원
    (우리는 원리 이해 위해 레거시부터 배움)
  • 스프링의 장점은 MVC 구조보다 DI다.
  • 스프링은 기본 서블릿을 지원 (우리가 직접 만들지 않고 스프링에서 만들어준다.)
    우리는 jsp, controller, service, dao만 만들면 됨

설치

  • sts 설치
    sts(Spring tool suite) : 스프링 개발 (환경 제공?) 툴 (이클립스 기반)
  • package 이제부터는 org.green.패키지 이름으로 적기 : 패키지 세번째 단어부터 ContextPath가 됨

스프링 이해

  • frontController 패턴 - 모든 요청을 일단 Servlet이 받음
  • HandlerMapping의 역할은 아래와 비슷하다
	ICmd cmdObj = cmds.get(cmd);
  • Controller의 역할은 아래와 비슷하다
	cmdObj.action(request);
  • ViewResolver의 역할은 아래와 비슷하다
	String nextPage = cmd + ".jsp";
  • servlet-context.xml에서 prefix(접두사=contextPath)와 subfix(접미사=.jsp)를 확인할 수 있다.
  • servlet-context.xml에서 <resources>를 통해 resources 폴더에 대한 접근 제어
    (servlet의 url-pattern과 같은 사용법 - jndi (Java Naming and Directory Interface)
    실제 주소와 들어오는 주소를 분리하여, 실제 주소가 바뀔 때 영향이 적음 = 의존성 낮춤)
	<!-- Handles HTTP GET requests for /resources/** -->
    <!-- by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />
  • resources : 정적 자원을 담은 폴더 (js, css 등)

  • ** : 모든 하위 폴더

  • servlet-context.xml에 annotation 기반으로 움직일 것 정의
    (bean 찾으라는 의미도 포함)

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

일 하는 로직을 담당하는 객체를 Cmd 객체라고 함 (자바 통용)
스프링에서는 이걸 Service 객체라고 부름

디자인 패턴 많이 들어감
퍼싸드 패턴 (복잡한 과정을 숨기고 겉면만 보여주는 패턴) 등

DAO 패턴
DB, repository, legacy에 접근하는 객체를 따로 두는 것

자바 Bean vs DTO
형태로는 같으나 의미하는 것이 조금 다름
Bean은 스펙 관점의 정의(이렇게 정의하라는 의미)
DTO는 쓰는 용도 관점에서 정의(이렇게 만들어서=이 형태로 사용하라는 의미)
(자바 Bean과 스프링 Bean은 다르다!)

  • 스프링은 @(annotation)을 통해 연결되는 cmd(service)를 결정
    클래스로 분리하여 Interface를 통해 가져올 때보다 형식이 자유롭지만(메서드 이름을 마음대로 지정할 수 있음) 형식을 제약할 수 없는 것이 또한 단점이기도 함.
    (자유롭다 vs 제약 불가 장단 존재)

어노테이션

Component 어노테이션 외

 * 어노테이션 의미 및 상속관계 정리
 * (어노테이션은 interface로 만들어지며 상속관계를 가질 수 있다!)
 * @Component : 빈으로 등록
 * - @Controller : Component 의미 + 컨트롤러로 사용
 * - @Service : Component 의미 + 커맨트 객체와 같은 역할
 * - @Repository : Component 의미 + DAO 클래스 역할
 * - @Configuration : + 구성 = 빈 여러개 등록시 활용 (중복빈 안만듦)

Bean 연결

@Controller
public class HomeController {
	@Autowired
	private Some s;
    ...
}
  • 이 경우 HomeController는 Some에 대해 의존성이 있다 (생성에 Some 객체가 필요)
    하지만 스프링에게 멤버변수 Some 객체에 대해 @autowired를 선언해주면, 스프링이 알아서 객체를 만들어준다.
    = 컨트롤러와 객체를 자동으로 연결(autowired)해준다.

아이콘 위 S 표시의 의미

  • 스프링이 관리하는 객체라는 의미

Bean 생성

  • xml / annotation / java code 로 생성
  • 실행 순서 : xml > annotation
    (xml 내에서는 순서 없음)
  • Bean은 기본적으로 싱글톤
    -> Bean이란 공유자원 = 'shared resources visible to all other web components'
    -> 값을 나타내는 객체는 Bean으로 등록하면 안됨

xml 방식

  • WEB-INF/spring/root-context.xml
    웹 어플리케이션 구성 요소들에게 보이는 공유 자원들을 정의하는 곳
    Root Context: defines shared resources visible to all other web components
    = Spring Bean으로 등록한다

  • xml 방식을 통해서만 같은 타입의 Bean 객체를 여러개 만들 수 있음!!

  • 기본 생성자 이외의 생성자를 통해 Bean 만들기 (패러미터 순서 주의!)

	<bean id="some1" class="org.green.first.Some" />
	<bean id="some2" class="org.green.first.Some">
		<constructor-arg value="custom" />
	</bean>
	<bean id="some3" class="org.green.first.Some">
		<constructor-arg value="7" />
		<constructor-arg value="custom" />
	</bean>
    // 같은 타입의 Bean 객체를 여러개 만드는 경우 = 보통 다른 생성자를 통해 객체를 만드는 것
	// 일반적으로는 잘 안 씀
  • scope 선택
scope
	singleton (default) : Bean 객체는 유일. 하나.
    prototype : 매번 새로 생성
    request : request마다 빈 생성
    session : session마다 빈 생성

annotation 방식

  • @Component : 클래스 앞에 달아 Spring Bean으로 등록
  • servlet-context.xml<context:component-scan>에서 처리
@Component
public class Dummy implements ISome {
	@Override
	public String toString() {
		return "dummy";
	}
}

<context:component-scan base-package="패키지명">
서블릿 생성시에 base-package 내부의 클래스를 scan해서 annotation을 확인한 후 빈을 등록한다.

java code 방식

1번

    @Component
    public class BeanMaker {
        @Bean
        public Some some1st() {
            return new Some();
        }
        @Bean
        public Some some2nd() {
            return new Some();
        }

        @Bean
        public SomeContainer someContainer() {
            return new SomeContainer(some1st());
        }
    }
  • some1st 객체가 두 번 만들어짐

2번

    @Configuration
    public class BeanMaker {
        @Bean
        public Some some1st() {
            return new Some();
        }
        @Bean
        public Some some2nd() {
            return new Some();
        }

        @Bean
        public SomeContainer someContainer() {
            return new SomeContainer(some1st());
        }
    }
  • 객체는 한 번만 만들어짐

Maven - 프로젝트 형상관리 도구

  • sts에 내장된 maven이 pom.xml의 dependencies에 작성된 라이브러리를 관리해준다.
  • C:\Users\사용자명\.m2\repository에 저장.

pom.xml

  • properties 값을 el 형태로 불러와서 사용 가능

의미

  • 객체를 직접 만들지 않아도 스프링이 만들어준다
    (멤버변수 위에 @autowired 어노테이션 표시
    <- 스프링아 Beans 중에 적당한 거 찾아서 알아서 만들어 연결해줘)
  • 연결 조건 : type 일치, 객체명과 beanId 일치, @Qualifier(String beanId)로 지정
    (조건에 맞는 클래스가 딱 하나만 나와야 함!)

bean id 정의

  • xml에서 id="id명" 정의
  • class명의 첫글자를 소문자로 전환하여 자동 정의
  • @Component(String beanId)로 정의

어노테이션은 인터페이스로 만든다.
우리가 만들수도 있다. 근데 안 만든다.

DI (Defendency Injection, 의존성 주입)

  • 객체간 결합도를 낮추고 유연성 확보
  • 무조건 정해진 규칙에 맞춰 결정된다는 것 (사람이 만들 때는 여지가 존재 = 불확실성)
  • 객체 생명주기(생성, 삭제, scope 등)

0607

  • 정리 안함
@Controller
public class PhoneController {
	@Autowired
	private IPhoneDao dao;
	
	@Autowired
	private PhoneService service;
	
	@RequestMapping(value={"/", "/list"})
	// @RequestMapping("/") : root로 들어오면 여기로 연결
	// @RequestMapping(value = {"/", "list"}, method = RequestMethod.GET) : 연결될 url과 method 결정
	public ModelAndView list(ModelAndView mav) {
		// 스프링이 알아서 넣어주는 패러미터들이 존재
		// 메서드를 자유롭게 정의할 수 있다는 것의 장점!
		
		// 속성을 속성이라 하지 못하고... Spring에서는 model이라 하게 됩니다...
		// HttpServletRequest 대신 Model을 사용 가능
		// 아니면 ModelAndView (= 속성에 붙여 넘길 정보(model)와 이동할 페이지 이름(view)을 가지는 객체)를 쓸 수 있음
		// ModelAndView는 파라미터로 받아와도 되고(자동 생성해줌) 아니면 내가 만들어도 됨
		
		mav.addObject("list", service.getAll());
		mav.setViewName("list");
		return mav;
	}
	
	@RequestMapping(value="/goInsertPhone", method=RequestMethod.GET)
	public String goInsertPhone() {
		return "insert";
	}
	// void로 return을 주지 않으면 들어온 주소로 다시 감
	
	@RequestMapping(value="/insertPhone", method=RequestMethod.POST)
	public String insertPhone(@ModelAttribute("yourPhone") Phone phone) {
		/*
		 *  request의 패러미터 받아오기
		 *  1. request 객체 요구해서, request.getParameter() 하기
		 *  2. @RequestParam(패러미터 이름) type 패러미터 받아올 변수명
		 *  패러미터명과 받아올 변수명이 같으면 어노테이션 생략 가능!!!
		 *  3. @RequestParam(value=패러미터 이름)
		 *  @RequestParam 내부 속성
		 *  - value=패러미터명
		 *  - required=boolean값 (어노테이션 생략시 false, 있으면 true)
		 *  required true인데 해당 parameter가 없으면 400Error
		 *  - defaultValue=기본값
		 *  4. @ModelAttribute
		 *  - 객체 생성
		 *  - 이름이 맞는 파라미터를 찾아 멤버변수에 대입해줌
		 *  - request 속성으로 삽입 (name=Class 첫글자 소문자)
		 */ 
		Connection con = dao.connect();
		dao.insertPhone(con, phone);
		dao.disconnect(con);
		return "redirect:list";
		// return String의 세 가지 형태
		// 1. jsp 페이지
		// 2. redirect + jsp페이지
		// 3. responsebody -> jsp를 거쳐 html로 변환하지 않고, 텍스트로 바로 보내는 것 (비동기 통신에서 활용)
	}
	
	@RequestMapping("/view/{p_id}")
	public String viewPhoneInfo(@PathVariable("p_id") int p_id, Model model) {
		// 파라미터로 받아오는 대신 url에 변수(p_id 정보)를 담아 보냄
		// url에 파라미터 정보를 받아옴 - restful 방식
		// url의 p_id => @pv에서 지칭하여 받아 => int p_id에 담기
		model.addAttribute("phone", service.getPhoneById(p_id));
		return "list";
	}
}
  • dao 하나로 모든 테이블에 접근하게 만들어도 됨
    하지만 서비스 객체를 테이블별로 분리하는 게 편할 것

0608

  • 정리 안함
		<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.47</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>	<!-- 자바로 따지면 이게 패키지 -->
			<artifactId>spring-jdbc</artifactId>	<!-- 자바로 따지면 이게 클래스명 -->
			<version>3.1.1.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/cglib/cglib -->
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>
  • jdbcTemplate
	<bean id="jdbcTmp" class="org.springframework.jdbc.core.JdbcTemplate">
		<constructor-arg ref="ds" />
	</bean>
// Dao 내부 메서드가 비슷하다 -> spring에서 servlet을 만들어주듯이, dao를 만들어주는 프레임워크가 있다.
// Dao를 편리하게 만들어주는 프레임워크 -> myBatis, springJdbc, 하이버네이트
// myBatis를 쓸 때 문제점 = 서로 다른 프레임워크를 사용하기 때문에 서로 버전 충돌 문제!
// springjdbc 버전은 스프링프레임워크 버전과 맞추면 된다.

// Configuration
// class가 아니라 메서드 return을 Bean으로 등록하는 방법
// 굳이 독립적 class로 분리할 필요 없을 때 사용 (ex. interface implements 하는 익명 이너클래스 등)
// ★ pom.xml에 cglib를 가져와야 함 (cglib 라이브러리에 의존성)
@Configuration
public class DaoHelper {
	@Bean
	public RowMapper<Phone> phoneMapper() {
		return new RowMapper<Phone>() {
			@Override
			public Phone mapRow(ResultSet rs, int rowNum) throws SQLException {
				return new Phone(
					rs.getInt("p_id"),
					rs.getString("p_model"),
					rs.getInt("p_price"),
					rs.getDouble("p_weight"),
					rs.getString("p_maker"),
					rs.getString("p_color"),
					rs.getString("p_year")
				);
			}
		};
	}
}
@Repository
public class SpringPhoneDao {
	@Autowired
	private JdbcTemplate jdbcTmp;
	@Autowired
	private RowMapper<Phone> phoneMapper;
	
	public int insertPhone(Phone phone) {
		String sql = "INSERT INTO phones (p_model, p_price, p_weight, p_maker, p_color, p_year) VALUES (?, ?, ?, ?, ?, ?)";
		return jdbcTmp.update(sql, phone.getP_model(), phone.getP_price(), phone.getP_weight(), phone.getP_maker(), phone.getP_color(), phone.getP_year());
	}
	
	public List<Phone> getAll() {
		String sql = "SELECT * FROM phones ORDER BY p_id DESC";
		List<Phone> list = jdbcTmp.query(sql, phoneMapper);
		return list;
	}
	
	public Phone getPhoneById(int p_id) {
		String sql = "SELECT * FROM WHERE p_id = ?";
		List<Phone> list = jdbcTmp.query(sql, phoneMapper, p_id);
		return list.get(0);
	}
	
	public int updatePhone(Phone phone) {
		String sql = "UPDATE phones SET p_model=?, p_price=?, p_weight=?, p_maker=?, p_color=?, p_year=? WHERE p_id=?";
		return jdbcTmp.update(sql, phone.getP_model(), phone.getP_price(), phone.getP_weight(), phone.getP_maker(), phone.getP_color(), phone.getP_year(), phone.getP_id());
	}
	
	public int deletePhone(int p_id) {
		String sql = "DELETE FROM phones WHERE p_id = ?";
		return jdbcTmp.update(sql, p_id);
	}
}

0609

  • util 사용하기 위해 Namespaces에 util 체크
  • properties를 사용하는 이점
    자바 코드를 그대로 둔 채로 파일 내용만 변경하여 사용할 수 있음
    dbms에 독립적이고 유연한 코드. 변경에 영향받지 않는 견고한 코드.

0612

  • ResponseBody : html 이외의 데이터(텍스트)를 응답으로 보낼 때 사용?
profile
welcome

0개의 댓글