스프링 필기
01. 스프링이란?
프레임워크
특정한 목적에 맞게 프로그래밍을 쉽게 하기 위한 약속
스프링(SPRING)
자바언어를 기반으로, 다양한 어플리케이션을 제작하기 위한 약속된 프로그래밍 틀
예전 EJB의 경우 고가의 장비가 필요 되어지고, 개발환경 및 설정 그리고 테스트 환경에 많은 애로사항들이 존재했다.
하지만 스프링의 경우 톰캣을 이용할 수 있다. EJB에 비해서 코드의 경량화 그리고 개발 중에 테스트가 쉽다는 점이 특징
국내 자바개발자들에게 표준프레임워크
02. 스프링 프로젝트 만들기
DI(Dependency Injection)와 IOC컨테이너
- DI(Dependency Injection)
- 방법1(내가 직접 객체를 생성한다.), 방법2(객체를 외부에 생성하여 넣어준다. 주입)
- 방법2가 더 좋다. (스프링 사용)
- IOC컨테이너
- 객체를 부품화 시키고, 그 부품들의 집합
03. DI(Dependency Injection) - I
04. DI(Dependency Injection) - II
05. DI 활용
- 규모가 커지고, 추후 유지보수 업무가 발생할 경우 DI를 이용한 개발의 장점이 될 수 있다.
- 자바파일의 수정 없이 스프링 설정 파일만을 수저앟여 부픔들을 생성/조립할 수 있다.
06. DI설정 방법
-
내부에서 'c:'는 constructor-arg의 약자, 'p:'는 property의 약자 -
위의 약자를 사용 하려면
xmlns:c=”http://www.springframework.org/schema/c”
xmlns:p=”http://www.springframework.org/schema/p” 를 추가해 줘야 한다.
JAVA로 DI설정
- @Configuration
이 클래스는 스프링 설정에 사용되는 클래스입니다. 라고 명시해 주는 어노테이션. 꼭 작성해야 한다. - @Bean
객체 생성 - 이렇게 만들어진 java파일의 class는 ‘AnnotationConfigApplicationContext’를 사용하여 호출하여 사용한다.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(<ClassName>.class);
xml안에 JAVA로 DI설정
-
을 선언하고, 그 아래에 <bean class=”<className>” />으로 config파일을 불러올 수 있다.
JAVA안에 xml로 DI설정
- @ImportResource(“classpath:<xml path>”)
JAVA파일안에 위와 같이 생성해 놓은 xml파일을 불러와 사용할 수 있다.
07. 생명주기와 범위
스프링 컨테이너 생명주기
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); // 생성
ctx.load("classpath:applicationCTX.xml"); // 설정
ctx.refresh();
// .load를 할 경우 .refresh()를 호출해줘야 한다.
Student student = ctx.getBean("student", Student.class); // 사용
System.out.println("이름 : " + student.getName());
System.out.println("나이 : " + student.getAge());
ctx.close(); // 종료
스프링 빈 생명주기
- 컨테이너에서 .refresh()를 호출 할 경우 bean이 생성된다.
- 컨테이너가 .close()로 소멸할 경우, bean도 같이 소멸하게 된다.
- bean만 소멸시키고 싶을 경우 beand에서 .destroy()를 호출하여 소멸시킨다.
- bean이 생성하고 소멸할 때에 실행되는 메소드를 만들고 싶을 경우
@PostConstruct, @PreDestroy
각 어노테이션을 생성, 소멸대 실행될 메소드위에 적어준다.
스프링의 범위
- 생성된 스프링 빈은 scope을 가지고 있습니다.
- 기본적으로 명시하지 않으면 scope=”singleton”으로 설정이 된다.
08. 외부파일을 이용한 설정
Environment 객체
ConfigurableApplicationContext ctx = new GenericXmlApplicationContext();
ConfigurableEnvironment env = ctx.getEnvironment();
// ctx의 Environmnet를 읽어 온다.
MutablePropertySources propert ySources = env.getPropertySources();
// env의 property들을 가져온다.
propertySources.addLast(new ResourcePropertySource("classpath:admin.properties"));
// property를 추가해 준다.
setAdminId(env.getProperty("admin.id"));
setAdminPw(env.getProperty("admin.pw"));
// 추출하여 사용한다.
xml파일에 프로퍼티 파일을 이용한 설정
<context:property-placeholder location="classpath:admin.properties, classpath:sub_admin.properties" />
// xml파일에 위와 같이 properties파일을 읽어와 사용한다. - ${ 변수명 }을 사용하여 값을 넣어줄 수 있다. (properties에 있는 변수명)
JAVA파일에 프로퍼티 파일을 이용한 설정
@Configuration
public class ApplicationConfig {
// propertices의 있는 내용을 바로 적용해준다.
@Value("${admin.id}")
private String adminId;
@Value("${admin.pw}")
private String adminPw;
@Value("${sub_admin.id}")
private String sub_adminId;
@Value("${sub_admin.pw}")
private String sub_adminPw;
@Bean
public static PropertySourcesPlaceholderConfigurer Properties() {
// 반드시 작성해야 하는 메소드. propertices를 설정한다.
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
Resource[] locations = new Resource[2];
locations[0] = new ClassPathResource("admin.properties");
locations[1] = new ClassPathResource("sub_admin.properties");
configurer.setLocations(locations);
return configurer;
}
@Bean
public AdminConnection adminConfig() {
AdminConnection adminConnection = new AdminConnection();
adminConnection.setAdminId(adminId);
adminConnection.setAdminPw(adminPw);
adminConnection.setSub_adminId(sub_adminId);
adminConnection.setSub_adminPw(sub_adminPw);
return adminConnection;
}
}
xml파일에 profile속성을 사용한 설정
profile="dev"
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.getEnvironment().setActiveProfiles(config);
ctx.load("applicationCTX_dev.xml", "applicationCTX_run.xml");
- beans의 속성으로 위와 같이 profile의 이름을 설정해 준다.
- java파일에서 아래와 같이 불러오면 profile의 이름이 config에 해당하는 파일을 읽어온다.
JAVA파일에 profile속성을 사용한 설정
@Profile("dev")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles(config);
ctx.register(ApplicationConfigDev.class, ApplicationConfigRun.class);
ctx.refresh();
- profile에 해당하는 .class파일을 읽어온다.
09. AOP (Aspect Oriented Programming) - I
AOP란?
- 공동 기능을 사용하는 경우 모든 모듈에 적용하기 위한 방법
- 상속의 경우는 다중 상속이 안 될 경우 공통기능 부여에 한계가 있다. 그리고 기능 구현부분에 핵심 기능 코드와 공통 기능 코드가 섞여 있어 효율성이 떨어진다.
-
AOP방법은 핵심 기능과 공통 기능을 분리 시켜놓고, 공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식입니다.
Aspect : 공통 기능 Advice : Aspect의 기능 자체 Jointpoint : Advice를 적용해야 되는 부분( ex, 필드, 메소드 ) (스프링에서는 메소드만 해당) Pointcut : Jointpoint의 부분으로 실제로 Advice가 적용된 부분, Jointpoint의 세분화 Weaving : Advice를 핵심 기능에 적용 하는 행위
XML기반의 AOP구현
의존성 설정
<!-- AOP : porm.xml에 작성 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
XML 파일 설정
<bean id="logAop" class="com.javalec.ex.LogAop" />
<aop:config>
<aop:aspect id="logger" ref="logAop">
<aop:pointcut id="publicM" expression="within(com.javalec.ex.*)" />
<aop:around pointcut-ref="publicM" method="loggerAop" />
</aop:aspect>
</aop:config>
공통 기능 클래스
public class LogAop {
public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
String signatureStr = joinpoint.getSignature().toShortString();
System.out.println( signatureStr + " is start.");
long st = System.currentTimeMillis();
try {
Object obj = joinpoint.proceed();
// 핵심 기능 실행
return obj;
} finally {
long et = System.currentTimeMillis();
System.out.println( signatureStr + " is finished.");
System.out.println( signatureStr + " 경과시간 : " + (et - st));
}
}
}
Advice의 종류
<aop:before> : 메소드 실행 전에 advice실행 (2번째로 많이 사용)
<aop:after-returning> : 정상적으로 메소드 실행 후에 advice실행
<aop:after-throwing> : 메소드 실행중 exception 발생시 advice실행
<aop:after> : 메소드 실행중 exception 이 발생하여도 advice실행
<aop:around> : 메서드 실행 전/후 및 exception 발생시 advice실행 (가장 많이 사용)
10. AOP (Aspect Oriented Programming) - II
11. 스프링 MVC 기초
스프링 MVC 개요
client가 요청을 하게 되면 DispatcherServlet이 모든 모듈을 통제하여 client에게 정보를 제공한다.
Controller를 거쳐 View를 사용자에게 보여준다.
스프링 MVC 구조
HomeController.java
: Controller의 내용을 작성하는 부분
/views
: View 내용을 작성하는 부분
servlet-context.xml
: View를 연결해 주는 부분
web.xml
: DispatcherServlet서블릿 맵핑, 스프링 설정 파일 위치 정의
12. 컨트롤러
요청 처리 메소드 제작
@RequestMapping("/board/view")
: 요청 경로(path)
return "board/view";
: 뷰페이지 이름
뷰에 데이터 전달
@RequestMapping("/board/conent")
public String content(Model model) { // Model 객체를 파라미터로 받음
model.addAttribute("id", 30); // Model 객체에 데이터를 담음
return "boadr/content";
}
@RequestMapping("/board/reply")
public ModelAndView reply() {
ModelAndView mv = new ModelAndView(); // ModelAndView 객체 생성
mv.addObject("id", 30); // Model 객체에 데이터를 담음
mv.setViewName("/board/reply"); // 뷰이름 설정
return mv;
}
13. Form 데이터
HttpServletRequest
@RequestMapping("boar/confirmId")
public String confirmId(HttpServletRequest httpServletRequest, Model model) {
String id = httpServletRequest.getParameter("id");
String pw = httpServletRequest.getParameter("pw");
model.addAttribute("id", id);
model.addAttribute("pw", pw);
retrun "board/confirmId";
} 값이 없어도 Error를 출력하지 않고 값을 출력하지 않고 화면을 보여준다.
@RequestParam
@RequestMapping("board/checkId")
public String checkId(@RequestParam("id")String id, @RequestParam("pw")int pw, Model model) {
model.addAttribute("identify", id);
model.addAttribute("password", ow);
return "board/checkId";
} 값이 없을 경우, 값 형식이 다를 경우 400Error를 출력한다.
데이터(커맨드) 객체
@RequestMapping("/member/join")
public String joinData(Member member) {
return "member/join";
} 값이 없어도 Error가 나지 않는다. 단, 파라미터의 이름은 객체의 내부의 변수 명과 이름이 일치해야한다.
@PathVariable
@RequestMapping("/student/{studentId}")
public String getStudent(@PathVariable String studentId, Model model) {
model.addAttribute("studentId", studentId);
return "student/studentView";
}
14. @RequestMapping 파라미터
@RequestMapping에서 Get방식과 Post방식
@RequestMapping에서 요청을 받을 때 Get방식과 Post방식으로 구분 할 수 있습니다.
<form action "student" method="get">
student id : <input type="text" name="id"> <br />
<input type="submit" value="전송"/>
</form>
@RequestMapping(method=RequestMethod.GET, value ="/student")
public String goStudent(HttpServletRequest httpServletRequest, Model model) {
Syetem.out.println("RequestMethod.GET");
String id = httpServletRequest.getParameter("id");
System.out.println("id : " + id);
model.addAttribute("studentId", id);
return "student/studentId";
}
@ModelAttribute
@ModelAttribute 어노이테이션을 이용하면 커맨드 객체의 이름을 개발자가 변경 할 수 있습니다.
@RequestMapping("/studentView")
public String studentView(StudentInformation studentInformation) {
return "studentView";
}
@RequestMapping("/studentView")
public String studentView(@ModelAttribute("studentInfo") StudentInformation studentInformation) {
return "studentView"
}
리다이렉트(redirect: 키워드)
다른 페이지로 이동할 때 사용합니다.
@RequestMapping("/studentConfirm")
public String studentRedirect(HttpServletRequest httpServletRequest, Model model) {
String id = httpServletRequest.getParameter("id");
if ( id.equals("abc") ) {
return "redirect:studentOk";
}
return "redirect:studentNg";
}
한글 처리
web.xml에 다음과 같은 코드를 넣는다.
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
폼 데이터 값 검증
client에서 값을 검사하는 것(Javascript, JQuery..)이 아니라 server에서 값을 검사하는 것
Validator를 이용한 검증
폼에서 전달 되는 데이터를 커맨드 객체에 담아서 전달을 한다. 이때 커맨드 객체의 유효성 검사를 할 수 있다.
@RequestMapping("/student/create")
public String studentCreate(@ModelAttribute("student") Student student, BindingResult result) {
String page = "createDonePage";
StudentValidator validator = new StudentValidator();
validator.validate(student, result);
if(result.hasErrors()) {
page = "createPage";
}
return page;
}
@Override
public boolean supports(Class<?> arg0) {
return Student.class.isAssignableFrom(arg0); // 검증할 객체의 클래스 타입 정보
}
@Override
public void validate(Object obj, Errors errors) {
System.out.println("validate()");
Student student = (Student)obj;
String studentName = student.getName();
if(studentName == null || studentName.trim().isEmpty()) {
System.out.println("studentName is null or empty");
errors.rejectValue("name", "trouble");
}
int studentId = student.getId();
if(studentId == 0) {
System.out.println("studentId is 0");
errors.rejectValue("id", "trouble");
}
}
15 ~ 20 게시판 만들기
MySQL 설정
// porm.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
// Servers/context.xml
<Resource
name="jdbc/[DBName]"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/[DBName]"
/>
// web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/[DBName]</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
DB연결
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/[DBName]");
Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
// ps.executeUpdate();
21. 스프링 JDBC
servlet-context.xml
<beans:bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource'>
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url" value="jdbc:mysql://localhost:3306/[DBName]" />
<beans:property name="username" value="root" />
<beans:property name="password" value="root" />
</beans:bean>
<beans:bean name="template" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
Controller.java
public JdbcTemplate template;
@Autowired
public void setTemplate(JdbcTemplate template) {
this.template = template;
Constant.template = this.template;
}
Constant.java
public class Constant {
public static JdbcTemplate template;
}
DAO.java
JdbcTemplate template = Constant.template;
Select
template.query(query, [저장형식]);
// template.query(query, new BeanPropertyRowMapper<BDto>(BDto.class));
template.queryForObject(query, [저장형식]);
Insert
this.template.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
String query = "";
PrepareStatement pstmt = con.prepareStatement(query);
pstmt.setString(#, [name]);
return pstmt;
}
});
String query = "";
this.template.update(query, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(#, [name]);
}
})
Update
String query = "";
this.template.update(query, new PrepareStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(#, [name]);
}
});
Delete
String query = "";
this.template.update(query, new PrepareStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(#, [name]);
}
})
출처 : 자바-JSP-Spring 강좌(https://www.youtube.com/playlist?list=PLieE0qnqO2kTyzAlsvxzoulHVISvO8zA9) 요약