반응형
반응형

📝 @RequestMapping, @Responsebody

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
    /**
     * GET /mapping/users
     */
    @GetMapping
    public String users() {
        return "get users";
    }
    /**
     * POST /mapping/users
     */
    @PostMapping
    public String addUser() {
        return "post user";
    }
    /**
     * GET /mapping/users/{userId}
     */
    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId) {
        return "get userId=" + userId;
    }
    /**
     * PATCH /mapping/users/{userId}
     */
    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId) {
        return "update userId=" + userId;
    }
}
  • 일반적으로 공통적인 URL을 클래스 위에 선언해 사용한다

 

@RequestMapping(value = "/modelAndView.do" method = RequestMethod.GET)
public ModelAndView returnModelAndView(HttpServletResponse response,
        HttpServletRequest request) {
    ModelAndView modelAndView = new ModelAndView();

    // WEB-INF/views/가 기본 경로
    modelAndView.setViewName("request"); // request.jsp 페이지 노출 WEB-INF/views/request.jsp
    modelAndView.addObject("name","James"); // index.jsp에 name : James 값을 전달

    return modelAndView;

}

 

리턴 종류  - ModelAndView 

  • 노출시킬 jsp 페이지와 값을 보낼 수 있습니다.
@RequestMapping(value = "/string.do")
public String returnString(HttpServletResponse response,
        HttpServletRequest request) {

    return "request"; // request.jsp 페이지 노출
}

 

리턴 종류 - String

  • return 값에 해당하는 jsp 페이지를 노출시킵니다.
@RequestMapping("/requset.do")
    public void request(HttpServletResponse response,
            HttpServletRequest request) throws IOException {

    PrintWriter writer = null;

    writer=response.getWriter();
    writer.print("<html><body><h1>Hello, ResponseBody!</h1></body></html>");
    writer.flush();
}

 

리턴 종류 - void

  • HTML 태그를 인식할 수 있습니다. 노출 페이지는 없지만 직접 만들 수 있습니다.

 

@RequestMapping(value = "/string2.do")
@ResponseBody
public String returnString2(HttpServletResponse response,
        HttpServletRequest request) {

    return "<html><body><h1>Hello, ResponseBody!</h1></body></html>";
}
// 이미지 base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
// mp4 base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = "video/mp4")
// pdf base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = "application/pdf")
// base64 디코딩해 해석해 화면에 노출
@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public @ResponseBody byte[] base64(HttpServletRequest request, HttpServletResponse response) throws Exception {

    String uri = "http://localhost:8080/getBase64";
    String encodeBase64 = callGetMethod(uri);

    byte decode[] = Base64.decodeBase64(encodeBase64);

    return decode;
}

리턴 종류 - String (responseBody)

  • jsp 페이지가 아닌 해당 문자열을 화면에 보여줍니다. (HTML 태그를 인식하고 JSON으로 데이터를 보낼 때 사용)
  • [JSON으로 데이터 보낼시 return type은 HashMap 입니다.]

 

 

📝 @RequestParam

@RequestMapping(value = "/param.do", method = RequestMethod.GET)
public void param(@RequestParam String name, String age,
    HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

    // 호출 URI : param.do?name=lee&age=20 // name 필수 입력
    System.out.println(">>> " + name);    // >>> lee
    System.out.println(">>> " + age);    // >>> 20


}

RequestParam은 무조건 해당 이름의 키로 받아야 한다는 강제성을 부여한다.

 

 

@ResponseBody
@GetMapping(value = "/test")
public String requestParamDefault(
        @RequestParam(required = true, defaultValue = "guest") String username,
        @RequestParam(required = false, defaultValue = "-1") int age) {
    log.info("username={}, age={}", username, age);
    return "ok";
}

옵션을 통해 Default값이나 required를 조작할 수 있다

 

📝 @ModelAttribute

@RequestMapping(value = "/model.do", method = RequestMethod.GET)
public void body4(@ModelAttribute BodyVO bodyVO,
    HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

    // 호출 URI : model.do?name=lee&age=20
    // @ModelAttribute 사용시에는 해당 클래스의 객체를 생성하고 값을 set 해준다. 
    // (default로 @ModelAttribute 안 적어도 @ModelAttribute 적은 거 처럼 동작)
    // 객체를 받는 경우는 무조건 쿼리스트링으로만 동작함 (body 인식 못 함)

    System.out.println(">>> " + bodyVO.getName());     // >>> lee
    System.out.println(">>> " + bodyVO.getAge());    // >>> 20

}

사용시 해당 클래스의 객체를 생성하고 값을 set 해준다. (default로 @ModelAttribute 안 적어도 @ModelAttribute 적은 거 처럼 동작)

객체를 받는 경우는 무조건 쿼리스트링으로만 동작함 (body 내용은 자동 DI 못 함)

 

 

📝 @ResponseBody, @RequestBody

@RequestMapping(value = "/urlencoded.do", method = RequestMethod.POST)
public void urlencoded(String code,String name) {

    // 호출 Url      : urlencoded.do?name=Lee
    // Content-Type : application/x-www-form-urlencoded
    // Body 		:  key → code, Value → ABC 
    System.out.println(">>> " + code); // ABC
    System.out.println(">>> " + name); // Lee 

    // 일반적으로 POST 방식에 쿼리스트링을 붙히지 않지만 붙혀도 인식이 가능함
    // x-www-form-urlencoded 의 경우 쿼리스트링처럼 code=ABC 인식을 한다.

}


/** application/x-www-form-urlencoded **/
@RequestMapping(value = "/urlencodedToObject.do", method = RequestMethod.POST)
public void urlencodedToObject(BodyVO bodyVO) {

    // 호출 Url      : urlencoded.do?name=Lee
    // Content-Type : application/x-www-form-urlencoded
    // Body 		:  key → code, Value → ABC 
    System.out.println(">>> " + bodyVO.getName()); // ABC
    System.out.println(">>> " + bodyVO.getAge()); // ABC


}
/** application/x-www-form-urlencoded의 GET의 경우 따로 RequestBody가 필요없다. **/

/** text **/
@RequestMapping(value = "/text.do", method = RequestMethod.POST)
public void text(@RequestBody String bodyContents) {

    // 호출 Url      : text.do
    // body 		: this is text
    // Content-Type : text 또는 text/html
    System.out.println(">>> " + bodyContents); // this is text

}


/** application/json **/
@RequestMapping(value = "/json.do", method = RequestMethod.POST)
public void json(@RequestBody String bodyContents) {

    // 호출 Url      : json.do
    // body 		: {"content" : "this is json"}
    // Content-Type : application/json
    System.out.println(">>> " + bodyContents); // {"content" : "this is json"}

}

/** application/json (Object Injection) **/
@RequestMapping(value = "/jsonToObject.do", method = RequestMethod.POST)
public @ResponseBody HashMap<String, Object> jsonToObject(@RequestBody BodyVO bodyVO) {

    /** BodyVO (HashMap도 또한 Object이기 떄문에 동일하게 적용 된다. **/
    // String name
    // String age → int 형으로 값을 보내면 못 자동 Injection이 안 된다. "age" : 20 (X)

    /** 참고로 BodyVO에 default값이 설정되어 있어도 ReuqestBody에 넘어온 값이 없다면(body에 json을 안 보내면) null로 덮어씌워진다. **/
    /** 필요사항에서는 데이터를 까서 검증하는 작업을 직접해야할 거 같다. **/


    // 호출 Url      : jsonToObject.do
    // body 		: {"name" : "lee", "age":"20"}
    // Content-Type : application/json
    System.out.println(">>> " + bodyVO.getName()); // lee
    System.out.println(">>> " + bodyVO.getAge()); // 20

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("bodyVO", bodyVO);

    return map;

}
/** responseBody란 처리한 결과를 클라이언트에게 다시 돌려줘서 읽을 수 있게한다. (즉 return 값이 있어야한다.) **/
// 미사용시 → 404 페이지를 찾을 수 없음
// 사용시 → {"bodyVO" : {"name" : "lee", "age":"20"}}

/**
 * jsonToObject.do을 사용하기 위해서는 하기 라이브러리가 필요 (body 내용을 Object에 Injeciton)
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.3</version>
</dependency>

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>
**/

 

@RequestMapping(value = "/deleteIndex", method = RequestMethod.GET)
@ResponseBody
public void deleteIndex(@RequestParam(value="No[]") ArrayList indexParams, HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    // http://localhost:8080/deleteIndex?No=keyword_index2
    ArrayList<String> indexNames = new ArrayList<String>();

    indexNames = indexParams;
    IndexInfo indexInfo = new IndexInfo();
    indexInfo.deleteIndex(indexNames);
}


<script>
	$(function() {
		$("#index_delete_btn").on("click", function() {

			var checked = [];
			$("input[name='No']:checked").each(function(i) {
				checked.push($(this).val());
			});

			$.ajax({
				type : "GET",
				url : "deleteIndex",
				data : {
					No : checked
				},
				success : function(data) {
					location.reload();
				}
              		error : function()
			}); // ajax 종료
		});
	});
</script>

<tbody id="indexVOs">
    <c:forEach var="indexVO" items="${indexVOs}" begin="0"
        end="${fn:length(indexVOs)}" step="1" varStatus="status">
        <tr>
            <td>${status.count}</td>
            <td>
                <input class="form-check-input" type="checkbox"
                    value=${indexVO.name } id="flexCheckChecked" name="No"></td>
            <td>${indexVO.status}</td>
            <td><a href="/indexDetail?name=${indexVO.name}&status=${indexVO.status}
                &docsCount=${indexVO.docsCount}&storeSize=${indexVO.storeSize}">${indexVO.name}</a></td>
            <td>${indexVO.docsCount}</td>
            <td>${indexVO.storeSize}</td>
        </tr>
    </c:forEach> 
</tbody>

 

RequestBody

  • RequestBody는 HTTP Body안에 JSON을 VO에 맵핑하는 스프링 어노테이션. 

 

ReponseBody

  • ResponseBody는 사용자가 읽을 수 있게 return 해준다. (outputStream으로 현재 화면에 flush하는 것과 같은 동작)

 

 

📝 @PathVariable (동적 URL 매핑)

// PathVariable에 userId에 값이 GetMapping에 {userId}에 들어간다

@GetMapping("/mapping/{userId}")
  public String mappingPath(@PathVariable("userId") String data) {
    log.info("mappingPath userId={}", data);
    return "ok";
}

// 2개도 사용 가능
@GetMapping("/mapping/{userId}/test/{orderNo}")
    public String mappingPath(@PathVariable("userId") String data, @PathVariable("orderNo") String data2) {
      log.info("mappingPath userId={}, orderNo={}", data, data2);
      return "ok";
  }

 

 

📝 @RequestHeader, @CookieValue

@GetMapping("/headers")
        public String headers(HttpServletRequest request,
                              HttpServletResponse response,
                              HttpMethod httpMethod,
                              Locale locale,
                              @RequestHeader MultiValueMap<String, String> headerMap,
                              @RequestHeader("host") String host,
                              @CookieValue(value = "myCookie", required = false) String cookie)
        {

            log.info("request={}", request);
            log.info("response={}", response);
            log.info("httpMethod={}", httpMethod);
            log.info("locale={}", locale);
            log.info("headerMap={}", headerMap);
            log.info("header host={}", host);
            log.info("myCookie={}", cookie);
            return "ok";
        }

 

 

📝@Slf4j (롬복 필요) , @RestController

package hello.springmvc;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController // @ResponseBody 역할
public class LogTestController {

    @GetMapping(value = "")
    public void testLog(){
        String helloWorld = "hello world";
        log.info("programming start : {}",helloWorld);
    }

}

Slf4j

  • 로깅하는데 도움을 줍니다.

 

RestController 

  • Controller + ResponseBody 역할을 합니다.

 

반응형
반응형
package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AutoAppConfigTest {

    private final String packageName = "hello.core";
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for(String beanDefinitionName : beanDefinitionNames){
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION && beanDefinition.toString().contains(packageName) == true) {
                System.out.println("beanDefinitionName = " + beanDefinitionName + " beanDefinition = " + beanDefinition);
            }
        }
    }
}

기본적으로 생성되는 Bean + 내가 만든 Bean = 전체 Bean 정보 

전체 Bean 정보에서 해당 Bean Class 정보가 내 패키지에서 만들어진 것인지 체크해서 보여준다)

반응형
반응형
import java.io.IOException;

import org.springframework.core.io.ClassPathResource;

public class test {

	public static void main(String[] args) throws IOException {

		ClassPathResource resource = new ClassPathResource("properties.ini");

		System.out.println("resource.getFile() : " + resource.getFile());
		System.out.println("resource.getFilename() : " + resource.getFilename());
		System.out.println("resource.getInputStream() : " + resource.getInputStream());
		System.out.println("resource.getPath() : " + resource.getPath());
		System.out.println("resource.getURL() : " + resource.getURL());
		System.out.println("resource.getURI() : " + resource.getURI());

		/**
		 * 
		 	resource.getFile() : F:\project\normal_spring_project\workspace\sample\target\classes\properties.ini
		 	resource.getFilename() : properties.ini
			resource.getInputStream() : java.io.BufferedInputStream@5ebec15
			resource.getPath() : properties.ini
			resource.getURL()) : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
			resource.getURI() : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
		 * 
		 */
		
	}

}

Spring에서 쉽게 가져올 수 있도록 제공해주는 라이브러리[ClassPathResource]로 쉽게 가져올 수 있습니다

가져올 경로는 src/main/resources가 기본 경로입니다

 

🔗참고 및 출처 

http://june0313.github.io/2018/08/11/read-resource-file-on-spring/

 

반응형
반응형

📝 Mybatis 연결하기

<bean id="dataSource"
    class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName"
        value="com.mysql.cj.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/customer?characterEncoding=UTF-8" />
    <property name="username" value="root" />
    <property name="password" value="1234" />

</bean>

<bean id="sqlSessionFactory"
    class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation"
        value="classpath:mybatis/mybatis-config.xml" />
    <property name="mapperLocations"
        value="classpath:mybatis/mappers/**/*mapper.xml" />
</bean>
<!-- classpath란 src/main/java를 의미한다. classpath:com.mycompany.myapp -->



<bean id="sqlSession"
    class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="sqlSessionFactory" />
</bean>

root-context.xml

<!-- Mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
</dependency>

<!-- Mybatis-Spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.2</version>
</dependency>

pom.xml

package com.company.macro;

import java.util.List;

import com.company.macro.VO.CustomerVO;

public interface MybatisImpl {

	public String selectCount();
	public List<CustomerVO> selectAll();
	public void insertAll();
	
//	@Select("SELECT * FROM customer")
//	public String selectAll();
}

MybatisImpl.java

 

query문의 이름과 반환 타입을 선언합니다.

public class CustomerVO {
	private String customer_no;
	private String customer_nm;
	// DB에 있는 컬럼명과 VO와 동일하게 가야한다.

	
	public String getCustomer_no() {
		return customer_no;
	}
	public void setCustomer_no(String customer_no) {
		this.customer_no = customer_no;
	}
	public String getCustomer_nm() {
		return customer_nm;
	}
	public void setCustomer_nm(String customer_nm) {
		this.customer_nm = customer_nm;
	}
	
	
}

CustomerVO.java

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 상기 내용은 반드시 필요한 내용 -->
<configuration>
   <properties>
        <property name="mybatis 안에서 사용될 column의 이름" value="디비 컬럼명" />
        <property name="tblCustomer" value="customer" />
        <property name="customer_no" value="customer_no" />
        <property name="customer_nm" value="customer_nm" />
        
        <property name="tblMember" value="tbl_member"/>
        <property name="colUserid" value="userid"/>
        <property name="colPassword" value="password"/>
        <property name="colEmail" value="email"/>
    </properties>

    <typeAliases>
        <typeAlias alias="customerVO" type="com.company.macro.VO.CustomerVO" />
    </typeAliases>
    <!-- VO가 들어있는 패키지명  -->
</configuration>

webapps/resources/mybatis-config.xml

 

property는 mapper.xml에서 쓰이는

typeAliases는 mapper.xml의 select해서 나온 데이터를 VO에 바로 담을수 있게 사용하겠다는 의미입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 상기 내용은 반드시 필요한 내용 -->

<!-- interface 명 -->
<mapper namespace="com.company.macro.mybatisImpl">

	<select id="selectCount" resultType="string">
		SELECT count(*) FROM customer
	</select>

	<select id="selectAll" resultType="customerVO">
		SELECT * FROM ${tblCustomer}
	</select>

</mapper>

webapps/resources/mappers/mapper.xml

 

resultType에는 typeAliases에 적은 VO를 사용할 수 있습니다.

${property name명} 으로 name에 해당하는 value를 가져올 수 있습니다.

 

 

 

📝 Mybatis 동작 구조

 

 

 

Mybatis 사용시 데이터 흐름

사용자 → 컨트롤러 → Servie(interface)[DI용 + 규격화] → ServiceImpl(class) → Dao(interface)[DI용 + 규격화] → mapper.xml(xml이지만 Dao에 설정된 interface를 따라감 implements한 class라고 생각하면 됨) → DB → 실행결과 → ServiceImpl → Controller → 사용자

 

Service → 비즈니스 로직 (DaoImpl을 통해 여러가지 쿼리문(Dao를 1개 이상 실행)을 가져오고 Java를 이용해 데이터를 만들어 반환 가능)

Dao       → DB Query 실행문이 들어감 (1개의 Query문)

mapper.xml → Query문에 대한 내용

Interface 사용 이유 → DI 하기 위함과 규격화를 위해 사용 → DI를 제대로 활용할 줄 몰라서 아직 와닿지 않음

 

* 참고 : 보통은 어떻게 처리하는지 모르겠지만 Service에 로직이 길어졌는데 해당 부분에 공통 로직이 있어서 (로그인 세션 체크 등...) 공통 API로 뺄 때 그 안에 Mapper를 이용해야하는 경우(DB Connection이 들어가는 로직)일 경우 해당 Util(공통 API)도 또한 Mapper를 Injection해서(Autowired) 사용할텐데 해당 Mapper를 이용하기 위해서는 @Component 또는 @Service 등 해당 클래스를 IoC컨테이너에 담아야한다.

 

LoginUtil util = new Util
LoginVo vo = util.getSessionInfo()
----------- (X)

@Autowired
LoginUtil loginUtil;

....

LoginVo vo = loginUtil.getSessionInfo();
----------- (O)

 

<!-- spring version과 spring-jdbc version은 동일해야한다 -->
<!-- mybatis, mybatis-spring, spring-version 서로 호환되는 버전으로해야한다. -->
<!-- 만약 호환 안 되는 버전 사용시 sqlSession 객체 만들 때 에러 나오는데 버전이 맞지 않습니다라 이런 에러도 안 나와서 에러 체킹이 힘듬 -->
<!-- root-context.xml에서 설정후 실행 시 sqlSession 객체 만들 때 정상 호환 버전들이면 정상 작동하거나 잘못 된 부분에 대한 정확한 에러가 나옴 -->


<properties>
    <java-version>11</java-version>
    <org.springframework-version>5.0.5.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
....

<!-- jdbc -->
<dependency>
  <groupId>org.mariadb.jdbc</groupId>
  <artifactId>mariadb-java-client</artifactId>
  <version>2.0.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>
<!-- Mybatis -->	
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!-- Mybatis + Spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="dataSource"
	    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	    <property name="driverClassName"
	        value="org.mariadb.jdbc.Driver" />
	    <property name="url"
	        value="jdbc:mariadb://192.168.0.40:7001/ocr_search" />
	    <property name="username" value="testid" />
	    <property name="password" value="testpassword" />
	</bean>

	<bean id="sqlSessionFactory"
	    class="org.mybatis.spring.SqlSessionFactoryBean">
	    <property name="dataSource" ref="dataSource" />
        <property name="configLocation"
        value="classpath:mybatis-config.xml" />
    	<property name="mapperLocations"
     	   value="classpath:mappers/*Mapper.xml" />
	</bean>
	
	<!-- classpath란 src/main/java 또는 src/main/resources를 의미한다. -->
	<!-- classpath는 build path - source에 등록된 경로들이다.  -->
	<!-- classpath:mybatis-config.xml → Alias등 설정 하는 설정 파일 -->
	<!-- classpath:mappers/*Mapper.xml → Query를 적는 파일이다 -->
	<!-- src/main/java/mappers 폴더에 관리하겠다는 의미이고 파일명이 Mapper.xml로 끝나는 파일들을 등록하겠다는 의미이다. -->
	
	<bean id="sqlSession"
	    class="org.mybatis.spring.SqlSessionTemplate">
	    <constructor-arg ref="sqlSessionFactory" />
	</bean>
	
	<!-- mapper 어노테이션을 인식 시키기위해 필요 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	    <property name="basePackage" value="com.company.ocrsearch" />
	</bean>
		
</beans>

root-context.xml

 

SqlSession : DB 연결하기 위한 객체 및 Query 수행 역할 (SqlSessionFactory가 주입 됨)

SqlSessionFactory : mapper.xml에 대한 설정 및 mapper.xml(쿼리문) 읽을 객체

 

 

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class EngineDto {

	private String uuid = "";
	private String id = "";
	private String password = "";
	private String salt = "";
	private String fail_cnt ="";
	
	public String getUuid() {
		return uuid;
	}
	public void setUuid(String uuid) {
		this.uuid = uuid;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}
	public String getFail_cnt() {
		return fail_cnt;
	}
	public void setFail_cnt(String fail_cnt) {
		this.fail_cnt = fail_cnt;
	}
	
	public String toStringShortPrefix() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
	
	
}

EngineDto.java

→ 데이터가 담기는 부분이다.

 

 

---- String 단일 매개변수 동적 쿼리 ----


import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

import global.configuration.Config;
import global.dto.DirectoryPathDto;
import global.dto.ServerInfoDto;


@Controller
public class EngineAPI {
	
	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/myabtis-test", method = RequestMethod.GET)
	public void testMybatis(String uuid) throws Exception{
		
		EngineDto engineDto = engineService.getUserInfo(uuid);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

→ Controller로 사용자의 요청이 들어오는 부분이다.

 


import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(String uuid) throws Exception;
}

EngineSerivce.java

→ 비즈니스 로직이 들어가며 규격화 및 DI 역할

 

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(String uuid) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(uuid);
		return engineDto;
	}

}

EngineServiceImpl.java

→ 실제 비즈니스 로직 구현한 것으로 DB 쿼리문을 사용할 경우 1개 이상의 Dao로 구성되어 있다.

받아온 쿼리문을 가지고 여러 동작을 하거나 여러개의 Dao를 호출해서 결과를 조합해서 Dto에 담아서 내려주는 형태

 

 

 

 

package com.company.ocrsearch.engine.dao;

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(String uuid) throws Exception;
	
}

EngineDao.java

→ root-context.xml에서 설정한 org.mybatis.spring.mapper.MapperScannerConfigurer에 포함된 패키지일 경우 @mapper 어노테이션을 찾아서 *mapper.xml과 연결해준다. interface이기 때문에 규격화및 DI 역할을 한다.

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="String"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			 FROM   admin_user	
			 WHERE 
			        uuid = #{UUID}
	</select>
</mapper>

EngineInfoMapper.xml 

→  쿼리문이 여기에 작성되며 연결할 interface명을 mapper namespace에 적는다.

xml을 EngineDao inteface를 implements한 class라고 생각하면 된다. 

 

id → Dao Interface에서 구현해야할 Funciton Name을 의미한다.

parameterType → 동적 쿼리를 위해 넘겨주는 파라미터를 의미한다. #{UUID}에 들어가는 파라미터는 String이 된다.

[ String 뿐만 아니라 HashMap 등이 있기 때문에 상황에 맞게 쓰면 된다 java.util.HashMap 등...)

String의 경우 HashMap의 경우 키 값으로 들어가기 때문에

resultType → 결과가 담길 곳을 의미한다. 일반적으로 여러개의 결과이고 데이터의 이동은 Dto에 담아서 하기 때문에 Dto를 적어줬다.

너무 당연한 이야기지만 내려받을 필드명과 Dto 필드는 같아야한다. (Alias 걸어서 Dto 수정 없이 Dto에 맞출 수도 있음)

[ String 뿐만 아니라 HashMap 등이 있기 때문에 상황에 맞게 쓰면 된다 java.util.HashMap 등...)

 

* 상속받는 놈(mapper.xml)이 ParameterType을 받기로 했기 때문에 Dao (interface)에도 그렇게 설정해줘야한다.

→ 매개변수가 1개의 String 이여야 함 (String의 경우 이름(#{UUID})을 정할 수 없기 때문에 들어온 그대로 들어가게 된다.)

     여러개의 매개변수를 받으려면 HashMap이나 Dto가 적당하다.

타입은 신경 안 쓰는 것 같다. → DB 필드가 문자 타입이여도 parameterType=int로 보내줘도 인식함

 

 

 

 

---- HashMap 매개변수 동적 쿼리 ----

 

pom.xml, root-context.xml, DTO는 동일합니다.

 

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;


@Controller
public class EngineAPI {
	
	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/mybatis-test", method = RequestMethod.GET)
	public void testMybatis(String uuid, String userId) throws Exception{
		
		HashMap<String, String> data = new HashMap<>();
		data.put("UUID", uuid); // mapper에서 대소문자 구분합니다.
		data.put("userId", userId);
		
		
		EngineDto engineDto = engineService.getUserInfo(data);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

 

import java.util.HashMap;

import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(HashMap<String, String> uuid) throws Exception;
}

EngineService.java

 

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(HashMap<String, String> uuid) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(uuid);
		return engineDto;
	}
}

EngineServiceImpl.java

 

import java.util.HashMap;

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(HashMap<String, String> uuid) throws Exception;
	
}

EngineDao.java

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="java.util.HashMap"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			 FROM   admin_user	
			 WHERE  uuid = #{UUID}
			   AND  id   = #{userId}
	</select>
</mapper>

EngineInfoMapper.xml

달라진 점은 HashMap을 파라미터로 넘긴다는 점입니다.

키의 값을 기준으로 동적쿼리가 생성되며 대소문자를 구분하니 주의하시길 바랍니다.

 

 

 

---- Dto 매개변수 동적 쿼리 ----

 

pom.xml, root-context.xml, DTO는 동일합니다.

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;


@Controller
public class EngineAPI {

	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/mybatis-test", method = RequestMethod.GET)
	public void testMybatis(EngineDto requestEngineDto) throws Exception{

		EngineDto engineDto = engineService.getUserInfo(requestEngineDto);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

 

 

import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(EngineDto requestEngineDto) throws Exception;
}

EngineService.java

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(EngineDto requestEngineDto) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(requestEngineDto);
		return engineDto;
	}
}

EngineServiceImpl.java

 

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(EngineDto requestEngineDto) throws Exception;
}

EngineDao.java

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="com.company.ocrsearch.engine.dto.EngineDto"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			  FROM  admin_user	
			 WHERE  uuid = #{uuid}
			   AND  id   = #{id}
	</select>
</mapper>

mapper.xml

 

 

 

 

 

https://wildeveloperetrain.tistory.com/26

 

@Component 와 @Bean, @Autowired 어노테이션 알아보기

자주 사용하면서도 정확하게 무슨 용도로 사용되는지, 어떤 동작 원리를 가지는지, 어떤 차이가 있는지 잘 몰랐던 부분에 대해서 공부합니다. 먼저 Annotation에 대해서 간단하게 알아보겠습니다.

wildeveloperetrain.tistory.com

 

반응형
반응형

 

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>

 

 

<!-- 경로 : main/resources/log4j2.xml -->
<?xml version="1.0" encoding="UTF-8"?>

<configuration status="DEBUG">

	<!-- 콜솔 -->
	<Console name="console" target="SYSTEM_OUT">
		<PatternLayout
			pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n" />
	</Console>

	<Appenders>
		<!-- 파일 -->
		<RollingFile name="as_api_param">
			<FileName>/home/Search/logs/search/search_param.log</FileName>
					<FilePattern>/home/Search/logs/search/search_param_%d{yyyy-MM-dd}.log
			</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>

		<RollingFile name="as_api_uri">
			<FileName>/home/Search/logs/search/search_uri.log</FileName>
			<FilePattern>/home/Search/logs/search/search_uri_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>
	</Appenders>

	<loggers>
		<Logger name="AS_API_PARAM" level="DEBUG" additivity="false">
			<AppenderRef ref="as_api_param" />

		</Logger>
		<Logger name="AS_API_URI" level="DEBUG" additivity="false">
			<AppenderRef ref="as_api_uri" />
		</Logger>
		<Logger name="CONSOLE" level="DEBUG" additivity="false">
			<AppenderRef ref="console"/>
		</Logger>
	</loggers>


</configuration>

Console → Console에 출력

RollingFile → 로그 찍는 형식 (Rolling이란 파일을 계속 갱신하는 것을 의미)
name → 로그 찍는 형식의 이름 (AppenderRef에서 사용)

FileName → 로그 저장경로와 로그 이름
FilePattern → Rolling시 저장될 위치및 로그파일 이름
PatternLayout  → 로그에 출력할 로그 내용 형식
%d{yyyy-MM-dd HH:mm:ss} → yyyy-MM-dd HH:mm:ss 로그 찍힌 시각
%5p → 로그형식
%C → 클래스명 표시
%m → 로그 출력 본 내용
%n → 각 플랫폼에 맞는 개행



TimeBasedTriggeringPolicy → 로그에 사용할 정책
interval → interval 단위로 로그 파일 새로 생성 (롤오버라고 한다)
FilePattern 에 적인 형식이 yyyy-MM-dd일 경우  interval=1 기준 1일 단위
yyyy-MM-dd-hh 일 경우는 1시간 단위
moulate → false인 경우 application 시작 시각으로부터가 기준이고 true인 경우 정각인 시각마다 롤오버가 일어난다.

Loggers → 위에 선언한 로그 형식중 사용할 로그 형식 선언
Logger 
 - name → java파일에서 사용할 Log의 이름
 - level → 로그 Level 해당 로그 이상만 로그 적재
 - addtivity → 중복 로깅 여부 (RollingFile name이 여러 AppenderRef ref에서 참조될 시 한번만 찍게 된다.)

package com.company.AS_API;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;




@Controller
public class companyController {
	
	@RequestMapping(value = "/logs", method = RequestMethod.GET)
	public void makeLogs {
		
		Logger console = LogManager.getLogger("CONSOLE");
		Logger APIParamLogger = LogManager.getLogger("AS_API_PARAM");
		Logger APIURILogger = LogManager.getLogger("AS_API_URI");

		// 로그 찍기
		APIParamLogger.debug("debug 입니다.");
		APIParamLogger.info("info 입니다.");
		APIParamLogger.warn("warn 입니다.");
		APIParamLogger.error("error 입니다.");
		APIParamLogger.fatal("fatal 입니다.");
	}
}

 

 

 

─── 참고 RollingFile + Console ── 

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

	<Appenders>
		<!-- 콜솔 -->
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n" />
		</Console>
		<RollingFile name="admin_real">
			<FileName>/home/Search/logs/admin/AA.log</FileName>
			<FilePattern>/home/Search/logs/admin/AA_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>
		<RollingFile name="admin_local">
			<FileName>D://logs//aa.log</FileName>
			<FilePattern>D://logs//aa_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"	modulate="true" />
			</Policies>
		</RollingFile>
	</Appenders>

	<loggers>
		<Logger name="ADMIN_LOGGER_LOCAL" level="DEBUG"
			additivity="false">
			<AppenderRef ref="console" />
			<AppenderRef ref="admin_local" />
		</Logger>

		<Logger name="ADMIN_LOGGER_REAL" level="DEBUG"
			additivity="false">
			<AppenderRef ref="console" />
			<AppenderRef ref="admin_real" />
		</Logger>
		
		
	</loggers>


</configuration>

 

 

형식 참고 블로그 : http://changpd.blogspot.com/2013/05/spring-lo4j.html

반응형
반응형

HTTP 통신 Request와 Response를 보기 좋게 보여주고 요청을 쉽게 도와주는 프로그램이다.

 

- 설치

https://chrome.google.com/webstore/search/postman?hl=ko

 

Chrome 웹 스토어

Chrome에 사용할 유용한 앱, 게임, 확장 프로그램 및 테마를 찾아보세요.

chrome.google.com

 

설치 후에 사용방법은 간단합니다.

 

 

Method가 Http 통신 방식을 정하시고 URL을 적어주시면 됩니다.

GET의 경우 웹브라우저로 요청해도 오니 POST방식을 알려드리겠습니다.

 

 

package com.lsj.chatting;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	@GetMapping("/test/get")
	public String hello() {
		return "<h1> get </h1>";
	}

	@DeleteMapping("/test/delete")
	public String delete() {
		return "<h1> delete </h1>";
	}
	
	@PostMapping("/test/post")  // Body : json → application/json (Text → text/plain로 요청시 에러 발생 [자동매핑이 안 되어서])
	public String post(@RequestBody Account account) { // MessageConverter라는 Class가 자동 Injection을 해준다.
		return "id : " + account.getId() + "\n password : " + account.getPassword(); 
		// {id:1,password:1234} 으로 요청 
	}
	
	@PostMapping("/test/post2") // Body : Text → text/plain 
	public String post2(@RequestBody String text) { // @requestBody body 데이터를 받기 위해 필요
		return text; // 정말로 맛있어요 으로 요청 
	} 
	
	@PutMapping("/test/put")
	public String put() {
		return "<h1> put </h1>";
	}
	
}
package com.lsj.chatting;

public class Account {

	private String id;
	private int password;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public int getPassword() {
		return password;
	}
	public void setPassword(int password) {
		this.password = password;
	}
	
	
}

기본적으로 form 따위 방식으로 보낼 때 x-www-form-urlencoded 방식으로 body에 담아 보냅니다. 

 

Header에 보시면 text/plain으로 보낸 걸 알 수 있습니다.

 

Body에 담아서 보낼 경우 Text 방식과 Json 방식을 설정할 수 있습니다.

 

반응형
반응형

📝 @Mapper (Mybatis)

@Mapper // XML (쿼리문 내용)을 여기에 DI 하겠다는 의미
public interface DashBoardMapper {
	
	List<LineChartDto> selectLineChartInfo() throws Exception;
	List<PieChartDto> selectEachCount() throws Exception;
	
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.company.ocr.mapper.DashBoardMapper">

	<select id="selectLineChartInfo"
		resultType="com.company.ocr.dto.LineChartDto">
			SELECT
				date_format(a.create_date,'%Y-%m-%d') AS cre_date,
				b.txt_type,
				COUNT(b.txt_type) AS type_count
			FROM 
				ocr_search AS a
					INNER JOIN
				ocr_search_data AS b
				ON a.ocr_no = b.ocr_no
			GROUP BY cre_date, b.txt_type
			ORDER BY cre_date
	</select>
	
	
	<select id="selectEachCount"
		resultType="com.company.ocr.dto.PieChartDto">
		SELECT 
			txt_type,
			COUNT(txt_type) AS type_count
		FROM
			ocr_search_data
		GROUP BY 
			txt_type
	</select>

</mapper>

Mybatis에서 제공해주는 어노테이션으로 XML 지시서 내용을 DI를 하겠다는 의미이다.

 

 

📝 @Component

@Component
public class DashBoardServiceImpl implements DashBoardService{

	@Autowired
	private DashBoardMapper dashBoardMapper; // 객체 생성

	@Override
	public List<LineChartDto> selectLineChartInfo() throws Exception {
		return dashBoardMapper.selectLineChartInfo();
	}

	@Override
	public List<PieChartDto> selectEachCount() throws Exception {
		return dashBoardMapper.selectEachCount();
	}

}

해당 클래스를 빈 객체로 생성한다

 

 

 

📝 @Repository

@Repository 
public class DashBoardServiceImpl implements DashBoardService{

	... 동일

}

DAO 관련 클래스이고 해당 클래스를 빈 객체로 생성한다

 

📝 @Service

@Service 
public class DashBoardServiceImpl implements DashBoardService{

	... 동일

}

비즈니스 로직을 수행하는 클래스이고 해당 클래스를 빈 객체로 생성한다

 

📝 @Controller

@Controller 
public class DashBoardServiceImpl implements DashBoardService{

	... 동일

}

 

스프링 MVC Controller이고 해당 클래스를 빈 객체로 생성한다

 

📝 @Autowired, @Qualifer

@Component
public class DashBoardServiceImpl implements DashBoardService{

	// @Qualifier("exam1") // id를 자료형이 아닌 이름으로 정해주고 싶을 때 사용한다.
	@Autowired
	private DashBoardMapper dashBoardMapper; // IoC컨테이너에 있는 같은 타입 Injection

	@Override
	public List<LineChartDto> selectLineChartInfo() throws Exception {
		return dashBoardMapper.selectLineChartInfo();
	}

	@Override
	public List<PieChartDto> selectEachCount() throws Exception {
		return dashBoardMapper.selectEachCount();
	}

}

Autowired

  • IoC 컨테이너에서 만들어진 빈 객체를 해당 필드에 DI한다 

Qualifier

  • 생성된 빈객체 이름으로 주입한다

우선순위 

    1. 타입 매칭 

    2. 타입 매칭 결과가 2개 이상일 경우 필드 명, 파라미터 명으로 빈 이름 매칭

 

 

📝 @Injection

@Component // Service 내용이 들어있다는 의미
public class DashBoardServiceImpl implements DashBoardService{

	@Inject
	private DashBoardMapper dashBoardMapper; // 객체 생성

	@Override
	public List<LineChartDto> selectLineChartInfo() throws Exception {
		return dashBoardMapper.selectLineChartInfo();
	}

	@Override
	public List<PieChartDto> selectEachCount() throws Exception {
		return dashBoardMapper.selectEachCount();
	}

}

 

Autowired 어노테이션과 유사

 

📝 @Resource

@Component // Service 내용이 들어있다는 의미
public class DashBoardServiceImpl implements DashBoardService{

	// @Resource(name = "propertiesService")
	@Resource
	private DashBoardMapper dashBoardMapper; // 객체 생성

	@Override
	public List<LineChartDto> selectLineChartInfo() throws Exception {
		return dashBoardMapper.selectLineChartInfo();
	}

	@Override
	public List<PieChartDto> selectEachCount() throws Exception {
		return dashBoardMapper.selectEachCount();
	}

}
/**  
Resource 사용하기 위해 필요한 라이브러리
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.2</version>
    </dependency>
**/

Autowired 어노테이션과 유사하다. (차이점 : Autowired와 다르게 이름으로 연결해준다.(필드 / 메서드에만 적용 가능))

 

📝 @Value

@Component
public class NewlecExam implements Exam {

	@Value("20")
	int kor;
	@Value("20") // 초기값 설정
	int math;
	
	
	public int getKor() {
		return kor;
	}

	public void setKor(int kor) {
		this.kor = kor;
	}

	public int getMath() {
		return math;
	}

	public void setMath(int math) {
		this.math = math;
	}

}

객체를 생성할 때(Component) 기본 값을 주입한다.

 

📝 @Component, @Configuration, @Bean

// @ComponentScan("di1.ui") // <context:component-scan base-package="di1.ui"/> 을 어노테이션 방식으로 변경
@ComponentScan({"di1.ui","di1"}) // scan 범위가 두개 이상일 경우 
@Configuration // 설정 파일이라는 뜻
public class NewlecDIConfig {
	
	@Bean // 빈 객체를 선언해 IoC 컨테이너에 담아라 라는 어노테이션이다.
	public Exam exam() { // exam → 함수명이 아니라 bean 객체의 id 이름을 의미한다.
		return new NewlecExam();
	}
	
	@Bean // 빈 객체를 선언해 IoC 컨테이너에 담아라 라는 어노테이션이다.
	public ExamConsole console() { // console → 함수명이 아니라 bean 객체의 id 이름을 의미한다.
		return new InlineExamConsole();
	}
}

ComponentScan

  • 해당 경로 하위에 있는 @Componet를 찾아 Bean객체를 생성해 IoC컨테이너에 넣는다

 

Configuration

  • 해당 클래스가 xml 지시서라는 의미이다. (설정 파일)

 

Bean

  • 빈 객체를 생성하라는 의미이다. (Bean 이름 설정 안 할시 함수명으로 생성)

 

📝 @GetMapping  옵션

// 특정 헤더 조건 매핑

@GetMapping(value = "/mapping-header", headers = "mode=debug")
  public String mappingHeader() {
      log.info("mappingHeader");
      return "ok";
}

// **미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume**

@PostMapping(value = "/mapping-consume", consumes = "application/json")
  public String mappingConsumes() {
      log.info("mappingConsumes");
      return "ok";
}

// 미디어 타입 조건 매핑 - HTTP 요청 Accept, produce
@PostMapping(value = "/mapping-produce", produces = "text/html")
  public String mappingProduces() {
      log.info("mappingProduces");
      return "ok";
}

 

📝 @PostMapping, @PatchMapping, @DeleteMapping

// 일반적으로 회원 목록 조회
@GetMapping(value = "/users")
public User getUsers(){
    ....
}

// 일반적으로 회원 등록
@PostMapping(value = "/user")
public User signupUser(){
    ....
}

// 일반적으로 회원 수정
@PatchMapping(value = "/user")
public User updateUser(){
    ....
}

// 일반적으로 회원 삭데
@DeleteMapping(value = "/user")
public User deleteUser(){
    ....
}

 

 

 

 

반응형
반응형
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>com.jsp.study.Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

xml에서 설정하는 방법입니다.

package com.jsp.study;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter("/*") // 모든 url 호출에 대해서 이 필터를 거친다.
public class Filter implements javax.servlet.Filter {



	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		response.setCharacterEncoding("UTF-8");			// 서블릿에서 직접 브라우저에 출력해줄 경우 쓴다 (out.print를 사용할 시)
		response.setContentType("text/html; charset=UTF-8");	// HTML이 UTF-8 형식이라는 것을 브라우저에게 전달한다.
		request.setCharacterEncoding("UTF-8");			// 파라미터에 해당하는 값을 UTF-8로 보내준다는 의미 (해당 로직에 POST 방식으로 데이터 보낼시)

		 System.out.println("before filter");
		 chain.doFilter(request, response); // 중간에 다른 Filter로 전이 시킬 수 있다.
		 System.out.println("after filter");
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// 서블릿 컨테이너가 필터를 초기화 시킨다.
		
	}

	@Override
	public void destroy() {
		// 인스턴스를 소멸하기 전에 호출하는 메소드
	}


}

annotation을 이용한 방법입니다.

 

- 동작 방식

init으로 서블릿 컨테이너가 필터를 초기화시킵니다. 그 후 doFilter로 원하는 행위를 진행 시킨 후에 ServletRequest(Controller)에 전달합니다. 처리 후 destory를 실행시킵니다. 만약 종료하기 전에 해주고 싶은 행위가 있으면 destory를 실행하면 됩니다.

 

반응형
반응형

📝Tiles

웹 페이지의 상단, 하단, 사이드바, ajax, 공통css 등과 같이 반복적으로 사용되는 부분에 정보를 모듈화해서 관리해줍니다.

즉 모듈관리 프로그램입니다.

 

JSP의 include같은 걸로 쓸수도 있지만 Tiles가 훨씬 우수합니다.
JSP Include 방식의 문제점은 매 JSP 페이지마다 모두 동일한 페이지들을 include 한다고 표시를 해야합니다.

만약 include 하는 페이지의 이름이 바뀌기라도 한다면 그에 해당하는 모든 페이지를 다 수정해야만 합니다.

 

 

<!-- spring 버전은 3.0.8 이상 필요 및 자바버전도 유의-->
<properties>
    <java-version>11</java-version>
    <org.springframework-version>5.2.7.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

<!-- Tiles -->
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>3.0.8</version>
</dependency>

pom.xml

 

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
    <beans:property name="order" value="2" />
</beans:bean>
<!-- load 순서 2번째 -->

<beans:bean
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <beans:property name="viewClass"
        value="org.springframework.web.servlet.view.tiles3.TilesView" />
    <beans:property name="order" value="1" />
</beans:bean>
<!-- load 순서 1번째 (tiles 설정파일) -->

<beans:bean
    class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <beans:property name="definitions"
        value="/WEB-INF/tiles.xml" />
</beans:bean>

<!-- load 순서 1번째에 쓰이는 tiles 설정파일 -->

servlet-context.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

  <definition name="*/*" template="/WEB-INF/views/include/layout.jsp">
    <put-attribute name="title" value="{2} - OCR" />
    <put-attribute name="header" value="/WEB-INF/views/include/top.jsp" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="aside" value="/WEB-INF/views/include/side.jsp" />
  </definition>
  <!-- definition name은 Controller의 */*형태의 return값을 받으면 해당 definition으로 분기시키겠다는 의미입니다.-->
  <!-- 예를 들어 Controller에서 페이지 리턴하려면 login/login_page 이런 형식으로 return할 때 {1} 에는 login이 들어가고 {2}에는 login_page가 들어가게 됩니다.
  <!-- 그리고 분기 페이지(template)는 layout.jsp 이라는 것입니다.--> 
  <!-- layout.jsp에서 각각 모듈로 된 걸 injection 하게 됩니다.-->
  <!-- put-attribute 은 layout에 넣을 요소 -->
  <!-- 위와 같은 방법으로 body는 동적으로 바뀌게 된다. -->
 
</tiles-definitions>

tiles.xml

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />

<!-- tiles.xml에서 선언한 name으로 각 모듈을 호출합니다. -->
<title><tiles:insertAttribute name="title" /></title>


<tiles:insertAttribute name="static" />
</head>

<body>

	<!-- header -->
	<tiles:insertAttribute name="header" />

	<div class="row">

		<!-- side -->
		<div class="col-1" id="layoutSide">
			<div id="layoutSidenav">
				<tiles:insertAttribute name="aside" />
			</div>
		</div>

		<!-- body -->
		<div class="col-9 mt-5" style="position: relative; left: 100px;">
			<tiles:insertAttribute name="body" />

		</div>
	</div>
	
</body>
</html>

layout.jsp (전체 구조)

 

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


<link href="<%=request.getContextPath()%>/resources/css/side_style.css"
	rel="stylesheet"><tiles:insertAttribute name="aside" />

<div class="sidebody">

	<div class="sidenavigation">
		<ul>
			<li class="sidelist active"><a href="test"> <span
					class="icon ps-4"><ion-icon name="albums-outline"></ion-icon></span>
					<span class="title ms-3">대시보드</span>
			</a></li>

			<li class="sidelist"><a href="listOcr"> <span
					class="icon ps-4"><ion-icon name="person-outline"></ion-icon></span>
					<span class="title ms-3">주민등록증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="car-outline"></ion-icon></span> <span class="title ms-3">운전면허증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="language-outline"></ion-icon></span> <span class="title ms-3">외국인등록증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="airplane-outline"></ion-icon></span> <span class="title ms-3">여권</span>
			</a></li>
		</ul>
	</div>
</div>


<script type="module"
	src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule
	src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
<script src="<%=request.getContextPath()%>/resources/js/script.js"></script>

side.jsp (사이드바)

 

<style>
@import
	url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap')
	;
</style>


<!-- CSS -->
<link
	href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
	rel="stylesheet"
	integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
	crossorigin="anonymous">
<link href="<%=request.getContextPath()%>/resources/css/styles.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/custom.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/common.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/bootstrap.css"
	rel="stylesheet" />
<link
	href="<%=request.getContextPath()%>/resources/css/search_result.css"
	rel="stylesheet" />
<link rel="icon" type="image/x-icon"
	href="<%=request.getContextPath()%>/resources/assets/img/favicon.png" />
	

<!-- JS -->
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<script
	src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

static.jsp (정적 소스)

 

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

<style>
background: linear-gradient(137deg, #fff6b7, #f77c99, #6578f2, #c2ffd8); background-size: 800% 800%; -webkit-animation: AnimationName 16s ease infinite; -moz-animation: AnimationName 16s ease infinite; -o-animation: AnimationName 16s ease infinite; animation: AnimationName 16s ease infinite; @-webkit-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @-moz-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @-o-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} }
</style>

<nav
   class="topnav navbar navbar-expand shadow justify-content-between justify-content-sm-start navbar-light m-0 p-0"
   id="sidenavAccordion" style="height:70px">
   <!-- Sidenav Toggle Button
   <button class="btn btn-icon btn-transparent-dark" id="sidebarToggle">
      <i data-feather="menu"></i>
   </button> -->
   <!-- Navbar Brand-->
   <!-- * * Tip * * You can use text or an image for your navbar brand.-->
   <!-- * * * * * * When using an image, we recommend the SVG format.-->
   <!-- * * * * * * Dimensions: Maximum height: 32px, maximum width: 240px-->
   <a href="test" class="ms-5 me-2"> <img
      src="<%=request.getContextPath()%>/resources/image/logo.png"
      ; style="width: 113px;">
   </a>
   
   <a href="doLogout" style="right: 0; color: #FFFFFF;" onclick="if(confirm('로그아웃 하시겠습니까?') == false)return false;"> 로그아웃 </a>
</nav>

top.jsp (상단)

 

 

footer.jsp는 저는 안 써가지고 따로 만들진 않았습니다.

 

 

 

 

 

- 참고용(여러가지의  - tiles 활용 방식)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

  <definition name="*/*" template="/WEB-INF/views/include/layout.jsp">
    <put-attribute name="title" value="{2} - Search" />
    <put-attribute name="header" value="/WEB-INF/views/include/top.jsp" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="aside" value="/WEB-INF/views/include/side.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>
  
  <definition name="*/*/*" template="/WEB-INF/views/include/none_layout.jsp">
    <put-attribute name="title" value="{3} - Search" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}/{3}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>
  
  <definition name="login" template="/WEB-INF/views/include/login_layout.jsp">
    <put-attribute name="title" value="login - Search" />
    <put-attribute name="body" value="/WEB-INF/views/login/login.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>

</tiles-definitions>

 

 

반응형