Sunday, April 19, 2020

[Spring] Respond ajax using Gson in the Spring

Why use Gson?

  On websites, clients and servers request and respond to each other via ajax. The request information sent in the form of a JSON Object should be received from the controller, processed several times, and then sent back the response information. Because ajax only receives response information in the form of a string, the controller must send a map or command object into the JSON Object string. In this situation, Gson allows you to make multiple objects into JSON Object strings.

Using Gson in the Spring

pom.xml
<!-- Gson -->
<dependency>
 <groupId>com.google.code.gson</groupId>
 <artifactId>gson</artifactId>
 <version>2.8.5</version>
</dependency>

toJson, fromJson Methods

 As a method in the Gson library, you can convert objects to JSON Object strings and JSON Object to a different type.

Basic Usage
Gson gson = new Gson();

// Object를 JSON Object 문자열로 반환
gson.toJson(Object)

// JSON Object를 해당 타입으로 바꿈
gson.fromJson(jsonObject, Class);

example
HashMap<String, Object> map = new HashMap<String, Object>();
JsonObject jsonObject = new JsonObject();

// Gson 객체 생성
Gson gson = new Gson();

// 맵을 JSON Object 문자열로 바꿈
String jsonString = gson.toJson(map);

// JSON Object를 맵으로 바꿈
gson.fromJson(jsonObject, new HashMap<String, Object>().getClass());  

Send VO Object to JSON

Controller
@ResponseBody
@RequestMapping(value = "/url", method = RequestMethod.POST)
public String questLoad(QuestVO questVO, Model model) throws Exception {
   
    List<QuestVO> questList = questService.selectQuestList(questVO);
  
    Gson gson = new Gson();
    HashMap<String, Object> map = new HashMap<String, Object>();
    
    // key-value 형태로 맵에 저장
    map.put("questList", questList);
   
   // 맵을 JSON Object를 바꾸고 다시 문자열로 바꿈
    String jsonString = gson.toJson(map);
  
    return jsonString;
}
 JSON Object requires a Property to be created, so you declare the map and add the Property and Value. Then use the toJson method to change the map to JSON Object string.

Ajax
$.ajax({
    url: "/url",
    type: "post",
    success: function(data) {  
        var obj = JSON.parse(data);
        
        /* obj = {"questList": ["questId": 1, "questTitle": "a"],
                               ["questId": 2, "questTitle": "b"]
                 }
         */       
        console.log(obj.questList[0].questId);
        // 1 출력
    },
    error: function(errorThrown) {
        alert(errorThrown);
    },
});
Request ajax to execute the controller method. The jsonString returned by the above method enters the data, which is the parameter of the access callback function. If you convert JSON.parse to JSON Object, you will be able to access the project.

[Spring] Using @RequestBody, @ResponseBody


Get JSON Data with @RequestBody

Enter the jackson library into pom.xml to convert JSON-type information into Map and Command objects.
pom.xml
<!--JSON-->
<dependency>
 <groupId>com.fasterxml.jackson.core</groupId>
 <artifactId>jackson-databind</artifactId>
 <version>2.9.3</version>
</dependency>

Ajax
var obj = {"name": "kim", "age": 30};

$.ajax({
    url: "/test",
    type: "post",
    data: JSON.stringify(obj),
    contentType: "application/json",
    success: function(data) {
        alert("성공");
    },
    error: function(errorThrown) {
        alert(errorThrown.statusText);
    }
});
 Ajax function to send requests to the controller. The two important points here are to send data using the JSON.stringify function and to set the contentType to "application/json". Otherwise, you will not be able to receive information with @RequestBody.


Convert JSON to Map Form
@Controller
public class MainController {
 
    @ResponseBody
    @RequestMapping("/test")
    public void init(@RequestBody HashMap<String, Object> map) {
    
     System.out.println(map);
     // {name=kim, age=30} 출력
    }
}
 Ajax function to send requests to the controller. The two important points here are to send data using the JSON.stringify function and to set the contentType to "application/json". Otherwise, you will not be able to receive information with @RequestBody.


Convert JSON to Object Form
@Controller
public class MainController {
 
    @ResponseBody
    @RequestMapping("/test")
    public void init(@RequestBody UserVO userVO) {
        
     userVO.getName(); // "kim"
        userVO.getAge(); // 30
    }
}
 At this time, the Property of the UserVO class must match the transmitted JSON object with the Property name and must have a getter, setter.


Foward JSON Data to @ResponseBody


To send Map Data
@Controller
public class MainController {
 
    @ResponseBody
    @RequestMapping("/test")
    public HashMap<String, Object> init(@RequestBody HashMap<String, Object> map) {
     
        map.put("phone", "0000-0000");
     return map;
        // {"name": "kim", "age": 30, "phone": "0000-0000"}가 data로 바인딩
    }
}
 When you return Map from a method with @ResponseBody, Map information is automatically converted and sent to JSON objects.

To send object Data
@Controller
public class MainController {
 
    @ResponseBody
    @RequestMapping("/test")
    public HashMap<String, Object> init(@RequestBody UserVO userVO) {
        
     HashMap<String, Object> map = HashMap<String, Object>();
        map.put("userVO", userVO);
        
        return map;
        // {"userVO": {name: "kim", age: 30}}가 data로 바인딩
    }
}
 Because object information is complicated to send as it is, it is made into a map shape and then returned and sent.

[Spring] Verifying Object Values with Bean Validation (JSR-303)


Enabling Bean Validation

pom.xml
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
 <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
 <version>5.2.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>5.2.1.Final</version>
</dependency>

servlet-context.xml
<beans:bean id="validator" 
            class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
Add a Validator bin to the servlet-context.xml.


Validation Annotation

 Use the following annunciations to check that the variable contains values that meet the conditions.

AnnotaionDescrption
@Size(min=m, max=n)Checks whether the string is m to n digits.
@NotNullCheck whether the variable value is null or not.
@NotBlankFor strings or arrays, check that they are not null and that they are not zero in length.
@Pattern("regrx")Examine whether the value of the variable meets the expression.
@EmailExamines variable values to satisfy email format.
@PastExamine if the time is in the past.
@FutureExamine if the time is in the future.
@AssertTrueChecks whether variable values are true.
@AssertFalseChecks whether variable values are false.

Using Validation annotations

  The Validation Annotation allows you to validate that the variable values meet these conditions.

MemberVO.java
public class UserVO {
 
    @Size(min=1, max=10)
    private String userId; // 1~10자리의 문자열
    private String password;
    private String passwordConfirm;
          ...
 Attach an annotation to the value of the field to which you want to apply the check. If you attach an annunciation as shown above, the variable must contain a string of 1 to 10 digits. Otherwise, it will cause an error.

member.jsp
<form:form modelAttribute="userVO" action="/test">
 <p>아이디</p>
 <form:input path="userId"/>
 <p>비밀번호</p>
 <form:input path="password"/>
 <p>비밀번호 확인</p>
 <form:input path="passwordConfirm"/>
 <input type="submit" />
</form:form>
Create a form tag to transfer values to userVO objects.

MemberController.java
@RequestMapping("/test")
    public String signUpSubmit(@ModelAttribute @Valid UserVO userVO, BindingResult result) {
  
        // 유효성 검사를 통과하지 못했을 때
        if (result.hasErrors()) {
            return "/signUp";
        
        // 유효성 검사를 통과했을 때
        } else {
            ...
            return "/main";
        }
        
    }
The value sent by @ModelAttribute will be contained in userVO. At this point, attach the @Vaild annoction to the object on which you want to run the validation and set the BindingResult result to the parameter. Then, if the validation fails, return to the page with the form tag and move on to the next page if it passes the validation.


Display error message on screen

 To display an error message on the screen, you need to do more work.

form:error Tag
<form:error path=userId cssClass="err"/>
 The form:error tag lets you float an error message for the userId variable. At this point, an error message is generated as a tag with the class attribute "err" so that the error message can be colored by css.

messages_ko_KR.properties
Size.userVO.userId = 아이디는 1~10자리이어야 합니다
Create /resources/messages/messages_ko_KR.properties file to create an error message. Error message said, "Annotation name.Object name.Variable name = Message.

servlet-context.xml
<!-- Register the Customer.properties -->
<beans:bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <beans:property name="basename" value="messages/messages" />
    <beans:property name="defaultEncoding" value="utf-8" />
</beans:bean>
 Register the messageSource bin in servlet-context.xml to use the contents of messages_ko_KR.properties as messages. When you finish all of this and run validation, the message you set at the time of the error will appear on the screen.

[Spring] Validator Validates Command Object Values

Validation

 For people who use the web application to sign up, they must enter a value on the specified form. However, validation should inform the user of the incorrect value because that value can be incorrect. Then let's try applying the Validator to validate the command object below.

MemberVO.java
public class MemberVO {
 
    private String userId;
    private String userPassword;
    private String userEmail;
            ...
}


Validator, Errors 

 Vaildator is the interface that you use to validate the value of an object, and Errors is the class that sends the verification results.

Extends Validator 
public class A implements Validator {

    @Override 
    public boolean supports(Class<?> clazz) {
    
    }
    
    @Override
    public void validate(Object target, Errors errors) {
    
    }
 First, create one class that implements the Validator interface. And override support, validation methods. The support methods help ensure that the Validator is the type that can be verified. The first parameter in the validation method also indicates the object to be verified.

public class MemberVaildator implements Validator {
    
    @Override 
    public boolean supports(Class<?> clazz) {
     return MemberVO.class.isAssignableFrom(clazz);
    }
    
    @Override
    public void validate(Object target, Errors errors) {
     MemberVO memberVO = (MemberVO) target;
        
        if (memberVO.getUserId() == null || memberVO.getUserId().length()<10) {
         errors.rejectValue("userId", "required");
        }
    }
 The support methods are written in the form of a validation object.class.isAssignableFrom (clazz), and return the contents of the support method to ensure that the object is of the type that can be Then, if the condition is satisfied using an if statement in the validation method, the rejectValue method in Errors will cause an error in the userId field with the required property.



Running the MemberVaildator

MemberController.java
@Controller
public class MemberController {
 
    public String MemberInit(@ModelAttribute MemberVO memberVO, BindingResult bindingResult) {
     new MemeberValidator().validate(memberVO, bindingResult);
        
        if(bindingResult.hasErrors()){ //validator에 에러가 있으면,
            return "login";  //이 페이지로 이동.
        }
    }
 Receives BindingResult as a parameter to the controller method and passes the bindingResult and the object to be verified by the forward factor of the validator. Next, under the terms of the if statement, determine whether the validation fails by using the hasError method to determine if an error is present in the validator.

[Spring] Interworking Spring with Mybatis

pom.xml

repository
<!--  오라클 드라이버 -->
<repositories>
 <repository>
  <id>codelds</id>
  <url>https://code.lds.org/nexus/content/groups/main-repo</url>
 </repository>
</repositories>
  A code that sets the repositivity to receive the Oracle driver library file, pasted it under the properties tag at the top.

data source, mybatis library
<!-- 데이터소스 관련 라이브러리 -->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>8.0.13</version>
</dependency>
<!-- 마이바티스 라이브러리-->
<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis</artifactId>
 <version>3.4.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>
Download the data source library and the Mybatis library required to connect to the database.

Oracle Driver Library
<dependency>
 <groupId>com.oracle</groupId>
 <artifactId>ojdbc6</artifactId>
 <version>11.2.0.3</version>
</dependency>
 Download the Oracle driver to connect to the Oracle database.


root-context.xml

 Paste the following code from the root-context file.

root-context.xml
<!-- 아파치 DBCP 설정 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
       <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe" />
       <property name="username" value="Id"/>
       <property name="password" value="Password"/>
</bean>
 
 A code that works with Oracle using a data source class. What you should pay attention to here are url, username, and password properties. xe in url property value means SID, which means that the database is not connected. The property value for username, password, then enter the ID and password of the account that accessed the database.

 <!-- SqlSessionFactory 객체 주입 -->
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="configLocation" value="classpath:/mybatis-config.xml"></property>
  <property name="mapperLocations" value="classpath:mappers/*Mapper.xml"></property>
 </bean>
 configLocation means the path to the Mybatis setup file and the path to the mapperLocations maper file. And '*Mapper.xml' means treating a file whose name ends with 'Mapper' as a maper file. In addition, 'classpath:' represents a path from the root directory to resources, and if you don't recognize it, you must click the project properties - java Build Path - source tab -browser to set the path.

<!-- Mapper 어노테이션을 탐색할 경로 지정-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.example.spring01.**.service.impl" />
</bean>
 configLocation means the path to the Mybatis setup file and the path to the mapperLocations maper file. And '*Mapper.xml' means treating a file whose name ends with 'Mapper' as a maper file. In addition, 'classpath:' represents a path from the root directory to resources, and if you don't recognize it, you must click the project properties - java Build Path - source tab -browser to set the path.


Create a Mybatis Settings File

 Create a Mybatis-Config file that allows you to set up multiple things related to the Mybatis. Make it in resources.

Mybatis-Config.xml
<?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>
 <settings> 
 <!-- 오라클 필드 속성이 READ_COUNT 처럼 언더 스코어가 있을 때 VOreadCount 처럼 카멜 케이스로 변환 되게 합니다. --> 
  <setting name="mapUnderscoreToCamelCase" value="true"/> 
 </settings>
 <typeAliases>
 </typeAliases>
</configuration>
 Create the Mybatis-Config file at the path location set in root-context as shown above.


Create Mybatis Mapper File

 Creates a map file that allows you to return the results of a query statement Create a mapers folder in webapp/resources and create HomeMapper.xml.

HomeMapper.xml
<?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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="com.example.portpolio.main.service.impl.MainMapper">
 <select id="selectLoginList" resultType="map">
  SELECT USER_ID, USER_PASSWORD
      FROM FIRST
 </select>
</mapper>
 First, enter the path of the maper interface with @Mapper attached with the namespace property value in the maper tag. Then enter the method name to return the query results to the id of the select tag. If you entered correctly, paste the query statement you want to execute into the select tag. The results of this query query return to the resultType's map (HashMap). If you attach a semicolon to a query statement as one thing to note, you will get an error.