매일 조금씩

01/29 ! - Spring MVC (3) : welcome 페이지 구현, 파일 업로드 구현(JSON, XML) , 데이터베이스 연결(직접연결, JdbcTemplate) 본문

빅데이터 플랫폼 구축을 위한 자바 개발자 양성과정

01/29 ! - Spring MVC (3) : welcome 페이지 구현, 파일 업로드 구현(JSON, XML) , 데이터베이스 연결(직접연결, JdbcTemplate)

mezo 2021. 2. 25. 20:00
728x90
반응형

Spring MVC template

구형버전이여서 활용시 유의사항이 있다.

 

Spring MVC Project 설정  =>  프로젝트 복사 (Properties 에서 Project setting에서 이름변경 해줘야함)

1. web.xml 수정

           /  ->  *.do

           utf-8 인코딩 필터 설정

2. Properties

          JRE System Library -> 버전 변경

          Project Facets -> Java 버전 변경

3. pom.xml

          JDK 버전 변경

          Spring Framework 버전 변경

          aspectj 버전변경  

          slf4j 버전 변경

4. 필요한 추가 라이브러리 설정

 

 

 

3-5. welcome 파일 지정 하기

http://localhost:8082/프로젝트명/*.jsp

http://localhost:8082/프로젝트명/

            => http://localhost:8082/프로젝트명/특정.jsp

 

WEB-INF 밖에 있는 시작 페이지를 실행시키면 바로 특정 jsp 파일이 뜨게한다.

먼저 시작 페이지에 다음과 같이 작성하고 

<%
	response.sendRedirect("index.do");
%>

web.xml에 아래 코드를 맨 위에 넣는다.

<welcome-file-list>
    <welcome-file>index.do</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

그러면

이렇게 실행된다. 시작과 함께 index.do를 요청하는 것이다.

 

 

 

 

 

[ fileupload lib ]

1. cos.jar

2. common-io / common-fileupload

3-6. 파일 업로드하기  -  cos.jar

> SpringWebEx01

1) cos.jar 를 프로젝트에 추가

파일을 업로드 하기 위해선 cos.jar가 필요하므로 maven repository에서 검색해서 pom.xml에 코드를 추가한다.

<!-- https://mvnrepository.com/artifact/servlets.com/cos -->
<dependency>
    <groupId>servlets.com</groupId>
    <artifactId>cos</artifactId>
    <version>05Nov2002</version>
</dependency>

cos.jar를 추가해줘야 MultipartRequest 클래스를 사용할 수 있다.

 

 

2) 다음 형식에 맞춰서 페이지에 작성한다.

         <form method="post" enctype="multipart/form-data"

         <input type="file" 

 

> write.jsp

<form action="write_ok.do" method="post" enctype="multipart/form-data">
파일: <input type="file" name="upload" />
<input type="submit" value="전송" />
</form>

 

3) webapp에 upload 폴더 생성

 

4) HomeController.java에 파일 업로드 코드 추가

@RequestMapping("/write.do")
public String write() {

    return "write";
}

@RequestMapping("/write_ok.do")
public String write_ok(HttpServletRequest request, HttpServletResponse response) {

    String uploadPath="C:\\Java\\java\\spring-workspace\\SpringWebEx01\\src\\main\\webapp\\upload";
    int maxFileSize = 1024 * 1024 * 2;
    String encType = "utf-8";

    MultipartRequest multi = null;


    try {
        multi = new MultipartRequest(request, uploadPath, maxFileSize, encType, new DefaultFileRenamePolicy());
        
        System.out.println(multi.getOriginalFileName("upload"));
		System.out.println(multi.getFilesystemName("upload"));

    } catch (IOException e) {
        System.out.println("[에러] " + e.getMessage());
    }

    return "write_ok";
}

 

 

 

5) 입력 받는 코드 (get 메서드)

<form action="write_ok.do" method="post" enctype="multipart/form-data">
데이터: <input type="text" name="data" /> <br /><br />
파일: <input type="file" name="upload" />
<input type="submit" value="전송" />
</form>

입력받는 페이지가 위와 같을 때 이것을 처리하는 controller 코드는 다음과 같다.

@RequestMapping("/write_ok.do")
public String write_ok(HttpServletRequest request, HttpServletResponse response) {

    String uploadPath="C:\\Java\\java\\spring-workspace\\SpringWebEx01\\src\\main\\webapp\\upload";
    int maxFileSize = 1024 * 1024 * 2;
    String encType = "utf-8";

    MultipartRequest multi = null;


    try {
        multi = new MultipartRequest(request, uploadPath, maxFileSize, encType, new DefaultFileRenamePolicy());

        System.out.println(multi.getOriginalFileName("upload"));
        System.out.println(multi.getFilesystemName("upload"));

        // text로 받을 때
        System.out.println(multi.getParameter("data"));

    } catch (IOException e) {
        System.out.println("[에러] " + e.getMessage());
    }

    return "write_ok";
}

 

파일은 아래의 두개 메서드를 사용해서 입력받은 값을 가져오고

  • getOriginalFileName() : 사용자가 입력 폼에서 직접 지정한 파일명을 리턴한다.
  • getFilesystemName() : type의 속성값이 file 인  input 태그에서 사용자가 선택한 파일 이름이 아니다. 사용자가 선택한 파일                                                 이 실제로 서버상의 폴더에 저장되었을 때의 파일명을 리턴한다. 왜냐하면 업로드시 파일명이 변경될                                                   수 있기 때문이다.

텍스트는 getParameter()를 사용한다.

 

 

 

3-7. 파일 업로드하기  -  common-io / common-fileupload

> SpringWebEx01

1) lib 가져와서 pom.xml에 추가하기

> pom.xml

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

 

2) 입력받는 파일 설정해주기 (파일크기, 언어 등 )

아래는 cos.jar 방식일때 controller 에서 이를 처리하는 방법이다. 

common-io / common-fileupload 방식일 땐 위와 다르다.

 

파일 크기 등 제한 사항들을 servlet-context.xml에서 beans로 선언하고 들어간다.

이때 크기 설정에서 value 값으로 연산자가 못들어가서 곱한후의 값 여기선 1Mbyte인 1040576을 쓴다.

임시데이터로 입력 파일을 잡고 그걸 넣어주는 형식이기 때문에 그 임시데이터의 크기 설정도 필요하다. 

> webapp > WEB-INF > spring > appServlet > servlet-context.xml

<!-- Upload Component 설정 -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.common.CommonsMultipartResoulver">
    <beans:property name="maxUploadSize" value="1040576" />
    <!-- 임시데이터 크기 설정 -->
    <beans:property name="maxInMemorySize" value="1040576" />
    <beans:property name="defaultEncoding" value="utf-8" />
</beans:bean>

 

3) 입력 받는 코드 (get 메서드)

> HomeController.java

@RequestMapping("/write_ok2.do")
public String write_ok2(@RequestParam("upload") MultipartFile multipartFile) {

    System.out.println("업로드 이름 : " + multipartFile.getName());
    System.out.println("파일 이름 : " + multipartFile.getOriginalFilename());
    System.out.println("파일 사이즈 : " + multipartFile.getSize());

    return "write_ok";
}
  • getOriginalFileName() : 사용자가 입력 폼에서 직접 지정한 파일명을 리턴한다.
  • geName() : 입력 받는 페이지의 입력 태그 name을 리턴한다.
  • getSize() : 업로드한 파일 크기를 리턴한다.

 

 

여기까진 임시데이터로 버퍼에 저장한 상태도 실질적으로 업로드는 여기서부터다.

 

4) 실제 업로드

// 파일 이름이 중복되면 오버라이팅됨 => DefaultRenamePolicy로 해결 가능
@RequestMapping(value = "/write_ok2.do")
public String write_ok2(@RequestParam("upload") MultipartFile multipartFile) {

    System.out.println("업로드 이름 : " + multipartFile.getName());
    System.out.println("파일 이름 : " + multipartFile.getOriginalFilename());
    System.out.println("파일 사이즈 : " + multipartFile.getSize());

    FileOutputStream fos = null;

    try {

        String uploadPath="C:\\Java\\java\\spring-workspace\\SpringWebEx01\\src\\main\\webapp\\upload";
        fos = new FileOutputStream(uploadPath + "\\" + multipartFile.getOriginalFilename());
        fos.write(multipartFile.getBytes());

    } catch (FileNotFoundException e) {
        System.out.println("[에러] " + e.getMessage());
    } catch (IOException e) {
        System.out.println("[에러] " + e.getMessage());
    }

    return "write_ok";
}

 

 

이런 파일 말고 json, xml, csv파일 업로드 방법도 알아야한다.

 

3-8. json, xml 파일 업로드

1) json-simple을 추가

 

2) view 페이지에 json데이터 출력

두가지 방법이 있다.

1. controller는 그냥 두고 view페이지에서 JSONArray와 JSONObject로 our.println하는 방법

> json1.jsp

<%@ page language="java" contentType="text/json; charset=UTF-8"
    pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>

<%@ page import="org.json.simple.JSONArray" %>
<%@ page import="org.json.simple.JSONObject" %>

<%
	JSONArray jsonArray = new JSONArray();

	JSONObject obj1 = new JSONObject();
	obj1.put("name", "name1");
	obj1.put("publisher", "publisher1");
	obj1.put("author", "author1");
	obj1.put("price", "price1");
	
	JSONObject obj2 = new JSONObject();
	obj2.put("name", "name2");
	obj2.put("publisher", "publisher2");
	obj2.put("author", "author2");
	obj2.put("price", "price2");
	
	jsonArray.add(obj1);
	jsonArray.add(obj2);
	
	out.println(jsonArray);
%>

 

2. view페이지는 그냥 두고 controller에서 Map으로 구현하는 방법

> HomeController.java

@RequestMapping(value = "/json2.do")
@ResponseBody
public String json2(Locale locale, Model model) {
    Map<String, String> map = new HashMap<String, String>();

    map.put("name", "name1");
    map.put("publisher", "publisher1");
    map.put("author", "author1");
    map.put("price", "price1");

    return JSONValue.toJSONString(map);
}

 

 

오브젝트는 Map이고 그걸 배열에 담고 싶으면 List를 사용하면된다.

> HomeController.java

@RequestMapping(value = "/json2.do")
@ResponseBody
public String json2(Locale locale, Model model) {
    List<Map> lists = new ArrayList<Map>();

    Map<String, String> map1 = new HashMap<String, String>();
    map1.put("name", "name1");
    map1.put("publisher", "publisher1");
    map1.put("author", "author1");
    map1.put("price", "price1");

    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("name", "name1");
    map2.put("publisher", "publisher1");
    map2.put("author", "author1");
    map2.put("price", "price1");

    lists.add(map1);
    lists.add(map2);

    return JSONValue.toJSONString(lists);
}

 

 

3-9. 데이터베이스 연결하기(1) - 직접연결

> SpringWebEx03

Spring에서 제공하는 jdbc 데이터베이스 연동 라이브러리를 사용한다.

1) mariadb를 pom.xml에 추가

> pom.xml

<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>2.7.1</version>
</dependency>

 

2) Spring JDBC를 pom.xml에 추가

 

3) spring-jdbc를 pom.xml에 추가한 후, 내 프로젝트 jdbc 버전과 맞게 버전 수정 후 저장

> pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

${org.springframework-version} 이걸 쓰면 내가 가지고 있는 것과 맞는 버전으로 세팅된다.

 

4) 데이터베이스와 관련한 설정 해주기

> root-context.xml

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="org.mariadb.jdbc.Driver" />
	<property name="url" value="jdbc:mysql://localhost:3307/sample" />
	<property name="username" value="root" />
	<property name="password" value="!123456" />
</bean>

 

servlet-context.xml에 넣어도 된다.

> servlet-context.xml

<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <beans:property name="driverClassName" value="org.mariadb.jdbc.Driver" />
    <beans:property name="url" value="jdbc:mysql://localhost:3307/sample" />
    <beans:property name="username" value="root" />
    <beans:property name="password" value="!123456" />
</beans:bean>

 

공통적인 부분이기때문에 root-context.xml에 넣는것이 더 효율적이다.

 

 

5) 데이터베이스 연동

[ @Autowired ]

> HomeController.java

@Controller
public class HomeController {
	
	@Autowired
	private DataSource dataSource;
	
	@RequestMapping(value = "/jdbc1.do")
	public String jdbc1(Locale locale, Model model) {
		// System.out.println("dataSource : " + dataSource);
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			conn = dataSource.getConnection();
			String sql = "select now() as now";
			pstmt = conn.prepareStatement(sql);
			
			rs = pstmt.executeQuery();
			if(rs.next()) {
				System.out.println("현재 시간 : " + rs.getNString("now"));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			if(rs != null) try {rs.close();} catch(SQLException e) {}
			if(pstmt != null) try {pstmt.close();} catch(SQLException e) {}
			if(conn != null) try {conn.close();} catch(SQLException e) {}
		}
		
		return "jdbc1";
	}
}

 

@Autowired 는 자동 검색 기능이다. 내부적으로 인스턴스화 된걸 찾아준다.

DataSource, JdbcTemplate, SampleDAO 등 인스턴스화가 필요한 것들을 new를 하지 않고 선언만 해주면 된다.

 

 

하지만 여전히 데이터베이스 연동코드가 매우 길다. 스프링에선 이부분을 간단한 코드로 작성할 수 있게  JDBC 코드용 기본  템플릿을 제공하고 있다. 그게 jdbcTemplate이다.

 

 

3-10. 데이터베이스 연결하기(2) - JdbcTemplate

[ JdbcTemplate ]

스프링에서 제공하는 SQL 연산들을 수행 할 수 있도록 해주는 JDBC 코드용 기본 템플릿을 말한다.

Spring Framework는 JdbcTemplate 클래스를 제공하며 반복코드 없이 손쉽게 DB와 연동할 수 있도록 구현되어 있다.

 

그 동안은 db에 연결하기 위해서는 여러가지를 선언해주어야 했다.

DriverManager, Connection..등등

JdbcTemplate을 이용하여 이런 것들을 통합하여 쉽게 데이터베이스와 연동할 수 있다.

[출처]   JdbcTemplate 작성자   멍요미 

 

세개의 메서드를 사용가능하다.

  • update() : 주로 SQL 연산을 통해 데이터베이스를 갱신시켜줄 때 사용한다.
  • queryForObject() : select 쿼리를 실행하여 한개의 객체를 받아올 때 사용한다.
  • query() 또는 queryForList() : queryForInt()가 하나의 결과 값을 위한 메소드인 반면, 많은 결과 값(로우 값)을 처리 할 수 있                                                             는 메소드이다.

root-context.xml에 아래 코드를 추가한다.

<!-- 데이터베이스 설정정보를 jdbc template이 가져감 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!-- <constructor-arg ref="dataSource"/> -->
    <property name="dataSource" ref="dataSource" />
</bean>

 

 

그리고 위쪽의 긴 코드를 jdbcTemplate를 사용하면 아래와같이 짧아진다.

> HomeController.java

@Controller
public class HomeController {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	// jdbcTemplate 사용
	@RequestMapping(value = "/jdbc2.do")
	public String jdbc2(Locale locale, Model model) {
		// System.out.println("jdbcTemplate : " + jdbcTemplate);
		
		// 데이터를 Object 형태로 가져온다. 다른것 형태로 해도 된다.
		String result = jdbcTemplate.queryForObject("select now()", String.class);
		System.out.println("result : " + result);
		
		return "jdbc1";
	}

}

 

 

그럼 model2 방식 처럼 dao를 사용해보자.

데이터베이스 연결은 dao에서 이뤄져야 하므로 jdbcTemplate을 dao에서 사용하게 된다.

> HomeController.java

@Controller
public class HomeController {
	
	@Autowired
	private SampleDAO dao;
	// spring한테 인스턴스화 된걸 가져오게 맡김 ( 아래에 new로 되었던게 없어짐 ) 

	// @Autowired + jdbcTemplate + dao 
	@RequestMapping(value = "/jdbc3.do")
	public String jdbc3(Locale locale, Model model) {
		// 생성자로 jdbcTemplate부를때
		// SampleDAO dao = new SampleDAO(jdbcTemplate);
		
		// @Autowired로 jdbcTemplate 부를때
		// SampleDAO dao = new SampleDAO();
		
		System.out.println(dao.selectNow());
		
		return "jdbc1";
	}
	
}

> SampleDAO.java

@Repository
public class SampleDAO {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	// controller에서 dao에 @Autoowired 사용하지 않을 때
//	public SampleDAO(JdbcTemplate jdbcTemplate) {
//		this.jdbcTemplate = jdbcTemplate;
//	}
	
	public String selectNow() {
		System.out.println("jdbcTemplate : " + jdbcTemplate);
		
		String result = jdbcTemplate.queryForObject("select now()", String.class);
		
		return result;
	}
}

 

 

 

 

응용실습) 직접연결과 JdbcTemplate를 사용한 우편번호 검색기

> ZipcodeMVCEx03

1. DataSource

2. JdbcTemplate

           google/naver

 

 

 

 

 

728x90
반응형