01. 스프링이란?
프레임워크
1
| 특정한 목적에 맞게 프로그래밍을 쉽게 하기 위한 약속
|
스프링(SPRING)
1
2
3
4
5
6
| 자바언어를 기반으로, 다양한 어플리케이션을 제작하기 위한 약속된 프로그래밍 틀
예전 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설정 방법
JAVA로 DI설정
- @Configuration
이 클래스는 스프링 설정에 사용되는 클래스입니다. 라고 명시해 주는 어노테이션. 꼭 작성해야 한다. - @Bean
객체 생성 - 이렇게 만들어진 java파일의 class는 ‘AnnotationConfigApplicationContext’를 사용하여 호출하여 사용한다.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(<ClassName>.class);
xml안에 JAVA로 DI설정
JAVA안에 xml로 DI설정
- @ImportResource(“classpath:<xml path>”)
JAVA파일안에 위와 같이 생성해 놓은 xml파일을 불러와 사용할 수 있다.
07. 생명주기와 범위
스프링 컨테이너 생명주기
1
2
3
4
5
6
7
8
9
10
11
12
| 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 객체
1
2
3
4
5
6
7
8
9
10
11
| 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파일에 프로퍼티 파일을 이용한 설정
1
2
| <context:property-placeholder location="classpath:admin.properties, classpath:sub_admin.properties" />
// xml파일에 위와 같이 properties파일을 읽어와 사용한다. - ${ 변수명 }을 사용하여 값을 넣어줄 수 있다. (properties에 있는 변수명)
|
JAVA파일에 프로퍼티 파일을 이용한 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| @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속성을 사용한 설정
1
2
3
4
5
| 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속성을 사용한 설정
1
2
3
4
5
6
| @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란?
XML기반의 AOP구현
의존성 설정
1
2
3
4
5
6
| <!-- AOP : porm.xml에 작성 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
|
XML 파일 설정
1
2
3
4
5
6
7
8
| <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>
|
공통 기능 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 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의 종류
1
2
3
4
5
| <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 개요
1
2
| 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"; : 뷰페이지 이름
뷰에 데이터 전달
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @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;
}
|
HttpServletRequest
1
2
3
4
5
6
7
8
| @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
1
2
3
4
5
6
| @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를 출력한다.
|
데이터(커맨드) 객체
1
2
3
4
| @RequestMapping("/member/join")
public String joinData(Member member) {
return "member/join";
} 값이 없어도 Error가 나지 않는다. 단, 파라미터의 이름은 객체의 내부의 변수 명과 이름이 일치해야한다.
|
@PathVariable
1
2
3
4
5
| @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방식으로 구분 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <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 어노이테이션을 이용하면 커맨드 객체의 이름을 개발자가 변경 할 수 있습니다.
1
2
3
4
5
6
7
8
9
| @RequestMapping("/studentView")
public String studentView(StudentInformation studentInformation) {
return "studentView";
}
@RequestMapping("/studentView")
public String studentView(@ModelAttribute("studentInfo") StudentInformation studentInformation) {
return "studentView"
}
|
리다이렉트(redirect: 키워드)
다른 페이지로 이동할 때 사용합니다.
1
2
3
4
5
6
7
8
9
10
| @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에 다음과 같은 코드를 넣는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <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를 이용한 검증
폼에서 전달 되는 데이터를 커맨드 객체에 담아서 전달을 한다. 이때 커맨드 객체의 유효성 검사를 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| @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 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // 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연결
1
2
3
4
5
6
| 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
1
2
3
4
5
6
7
8
9
10
| <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
1
2
3
4
5
6
7
| public JdbcTemplate template;
@Autowired
public void setTemplate(JdbcTemplate template) {
this.template = template;
Constant.template = this.template;
}
|
Constant.java
1
2
3
| public class Constant {
public static JdbcTemplate template;
}
|
DAO.java
1
| JdbcTemplate template = Constant.template;
|
Select
1
2
3
4
| template.query(query, [저장형식]);
// template.query(query, new BeanPropertyRowMapper<BDto>(BDto.class));
template.queryForObject(query, [저장형식]);
|
Insert
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 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
1
2
3
4
5
6
7
| String query = "";
this.template.update(query, new PrepareStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(#, [name]);
}
});
|
Delete
1
2
3
4
5
6
7
8
9
10
| 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) 요약
|