1. Maven Archetype

Archetype이란 Maven(Spring, Spring boot)에서 나만의 template/boilerplate를 제작하는 방법이다.

 

2. 기본세팅

2.1 Setting.xml

- Archetype 사용하기 위해선 setting.xml 파일이 필요하다.

- setting.xml 파일이 없다면, 내문서의 .m2 폴더에 setting.xml 파일을 생성한다.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">


  <localRepository>${user.home}/.m2/repository</localRepository>

</settings>

 

2.2 Maven

https://maven.apache.org/download.cgi

 

Maven – Download Apache Maven

Downloading Apache Maven 3.6.3 Apache Maven 3.6.3 is the latest release and recommended version for all users. The currently selected download mirror is http://us.mirrors.quenda.co/apache/. If you encounter a problem with this mirror, please select another

maven.apache.org

- Archetype은 기본적으로 Maven명령어를 사용하기 때문에 Maven이 설치되어 있어야 한다.

- 위 사이트에 접속하여 .zip 파일을 다운받아 적절한 위치에 압축을 해제한 뒤 고급시스템 설정의 path에

압축 해제한 경로에 맞게(Ex : C:\apache-maven-3.6.3\bin) path를 추가한다.

 

※ Spring/Spring Boot는 Maven 설치안하는데 Maven이 되는데, 그 이유는 Spring/Spring Boot의 경우 프로젝트를 생성하게 되면, 자동으로 mvnw.cmd 라는 파일이 생기기 때문이다.

 

3. Archetype 사용방법

3.1 미리 생성한 프로젝트에서 생성 후 로컬배포

- Spring/Sprin Boot에서 나만의 template/boilerplate를 제작하였다면, IDE Terminal에서 프로젝트 Root 경로에 아래의 명령어를 입력한다

mvn archetype:create-from-project

 

- 명령어를 입력하게되면 target/generated-sources/archetype 폴더가 생성된다. 생성한 폴더에 접근한다.

cd target/generated-soruces/archetype

 

- IDE Terminal에서 mvn install 또는 mvn deploy를 실행한다.

mvn install

  - mvn install은 local 저장소에 배포를 하며, .m2 폴더에 저장된다.

  - mvn deploy는 maven 저장소에 배포하는 것이며, 사설 nexus 저장소에 배포가능하다.

 

 

- mvn archetype:generate -DarchetypeCatalog=local 명령어를 통해 정상적으로 등록되었는지 확인한다.

mvn archetype:generate -DarchetypeCatalog=local

 

- mvn install 했으나 로컬에 배포되지 않은 경우 mvn archetype:update-locate-catalog 를 입력한다.

mvn archetype:update-locate-catalog

 

3.2 사설 저장소에 배포

- mvn deploy로 사설 nexus에 등록할 경우 target/generated-soruces/archetype 에 있는 pom.xml에 아래와 같이 등록한다. 

	<distributionManagement>
        <repository>
            <id>test-releases</id> 
            <name>Releases Repository</name>
            <url>http://127.0.0.1/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>test-snapshots</id>
            <name>Snapshots Repository</name>
            <url>http://127.0.0.1/repository/maven-snapshots/</url> 
        </snapshotRepository>
    </distributionManagement>

 

- 만약 사설 저장소에 권한이 필요해 계정 및 비밀번호가 필요하면, .m2 폴더의 settings.xml에 계정과 비밀번호를 등록한다. server에 들어가는 id 와 위 xml의 id가 같아야한다.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">


  <localRepository>${user.home}/.m2/repository</localRepository>

  <servers>
    <server>
      <id>test-releases</id>
      <username>admin</username>
      <password>testpw</password>
    </server>
     <server>
      <id>test-snapshots</id>
      <username>admin</username>
      <password>testpw</password>
    </server>

  </servers>
 
</settings>

 

- 등록 후 target/generated-soruces/archetype 경로에서 mvn deploy를 하면 사설저장소에 저장된다.

- 사설 저장소에 있는 것을 사용 및 확인하고 싶다면 setting.xml에 mirror를 작성해줘야 한다.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">


  <localRepository>${user.home}/.m2/repository</localRepository>

 <mirrors>
	<mirror>
	<id>test-snapshots-repo</id>
	<mirrorOf>*</mirrorOf>
	<name>Mirror.</name>
	<url>http://127.0.0.1/repository/maven-snapshots/</url>
	</mirror>
</mirrors>

  <servers>
    <server>
      <id>test-releases</id>
      <username>admin</username>
      <password>testpw</password>
    </server>
     <server>
      <id>test-snapshots</id>
      <username>admin</username>
      <password>testpw</password>
    </server>

  </servers>
 
</settings>

 

- 등록 후 mvn archetype:generate 하면 등록한 archetype 항목이 나올것이다.

 

4. 프로젝트 생성

- mvn archetype:generate 명령어 후 플젝 선택시 입력하는 것들은

target/generated-soruces/archetype 폴더의 pom.xml에 있는

- groupid

- artifactId

- version

이며, 똑같이 입력해주면 프로젝트가 생성된다.

 

1. 먼저 필요한 Maven을 설치합니다.

아래의 메이븐저장소에 들어가서 spring-security-core, spring-security-web, spring-security-config, pring-security-taglibs 검색하여 pom.xml에 추가합니다.

https://mvnrepository.com/

 

Maven Repository: Search/Browse/Explore

Reactivewizard Binding Last Release on Oct 31, 2019

mvnrepository.com

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>

 

2. web.xml 에 들어가 아래와 같이 추가합니다.

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/root-context.xml
		/WEB-INF/spring/security-context.xml
	</param-value>
</context-param>

<filter>
	<filter-name>springSecurityFilterChain</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy
	</filter-class>
</filter>
    
<filter-mapping>
	<filter-name>springSecurityFilterChain</filter-name>
	<url-pattern>/*</url-pattern>

</filter-mapping>

 

3. 로그인 창을 하나 만듭니다.

파일이름은 login.jsp로 만들었습니다.

<!-- login.jsp -->
<form action="loginProcess" method="post">
<input type="text" name="userId">
<input type="password" name="userPw">
<input type="submit" value="ok">
</form>

 

4. /WEB-INF/spring 폴더 밑에 security-context.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"

	xmlns:security="http://www.springframework.org/schema/security"

	xmlns:context="http://www.springframework.org/schema/context"

	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


	<security:http auto-config='true' use-expressions="true">
		<security:csrf disabled="true" />
        
		<security:intercept-url pattern="/login"
			access="permitAll" />

		<security:intercept-url pattern="/**"
			access="isAuthenticated()" />

		<security:form-login login-page="/login"
			username-parameter="userId" password-parameter="userPw"
			login-processing-url="/loginProcess" default-target-url="/test"
			authentication-failure-url="/login?failure"
			always-use-default-target='true' />
            
		<security:logout invalidate-session="true"
			logout-url="/logout" logout-success-url="/login?logout" />
	</security:http>


</beans>

대충 설명하자면 /login 주소는 권한이없어도 접속을 허용하겠다는 뜻이고

그 외 주소는 로그인 인증이 되어야 접속할 수 있도록 하겠다는 뜻입니다.

그 외를 알고싶으시면 use-expressions(SpEL) 을 찾아보시면 됩니다.

그리고 3번에서 만든 로그인페이지를 등록하고 3번에서 만든 각각 id, passwordname들을 지정합니다.

또한 login-proccessing-url에 3번에서 만든 action 의 주소를 입력합니다. 여기서는 loginProcess로 되어있지만 아무거나 해도됩니다.

login-proccessing-url은 로그인 처리를 해주는 url인데 이름만 정해주면 security 측에서 알아서 만들어주는 url으로써  이름만 정하면 따로 저희가 할 일은 없이 spring security가 로그인처리를 진행 해줍니다.

default-target-url은 로그인성공시 접속할 주소를 입력합니다.

auauthentication-failure-url 은 로그인 실패시 처리할 주소를 입력하시면 됩니다.
always-use-default-target='true' 로그인 성공후 default-target-url에 설정한 곳으로 갈지 선택하는 것입니다.

invalidate-session="true" logout-url="/logout" logout-success-url="/login?logout" 로그아웃 입니다. 로그아웃 경로를 저장하고 로그아웃 성공시 돌아갈 경로를 저장해주면 로그아웃이 됩니다. 이 로그아웃url 또한 security 측에서 알아서 만들어주는 url으로써 여기서 이름만 정하면 따로 저희가 만들일 없이 spring security가 알아서 로그아웃을 진행해 줍니다.

 

5. 그리고 위의 security-context.xml 안에 로그아웃 밑에 바로 아래와 같이 추가합니다.

	<security:authentication-manager>

		<security:authentication-provider

			user-service-ref="loginService">

			<security:password-encoder

				ref="bcryptPasswordEncoder" />

		</security:authentication-provider>

	</security:authentication-manager>


	<bean id="loginService" class="net.test.test.service.testService" />

	<bean id="bcryptPasswordEncoder"

		class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

로그인 진행시 아이디를 가지고 비밀번호를 비교할 서비스클래스를 정하는 것입니다.

또한 데이터베이스에 비빌번호가 bcrypt로 저장되어 있을 경우 비밀번호 비교시 bcrypt로 비밀번호를 비교하기 위해 설정해줍니다.

 

6. 위에서 아이디를 가지고 비밀번호를 비교할 서비스를 생성합니다.

여기서 DB베이스에서 회원정보를 불러와 암호화되어있는 비밀번호를 비교하게됩니다.

public class testService implements UserDetailsService {

	@Autowired
	TestDAO testDAO;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		loginVO userVO = testDAO.selectLogin(username);

		if (userVO == null) {
			throw new UsernameNotFoundException("No user found with id");

		}

		Collection<SimpleGrantedAuthority> roles = new ArrayList<SimpleGrantedAuthority>();

		roles.add(new SimpleGrantedAuthority("ROLE_USER"));

		UserDetails user = new User(userVO.getId(), userVO.getPassword(), roles);
		return user;

	}

}

UserDetailsService라는 것을 implements합니다.

그리고 username을 통해 데이터베이스에서 회원정보를 가져오고

roles에 유저를 선택한 다음 UserDetails를 생성하여 return 만 해주면 Spring Security가 알아서 비밀번호를 데이터베이스에 있는 것과 form에서 넘어온 비밀번호를 비교하여 맞으면 로그인성공해주고 아니면 로그인실패를 해줍니다.(그냥 조회만 했을 뿐인데 알아서 다 해줌)

 

이렇게 bean설정과 UserDetails만 설정하면 로그인form에서 아이디하고 비밀번호를 전달한 뒤 아이디만 조회했을 뿐인데 spring security가 로그인처리까지 다 진행해줍니다.

다음 controller에서 Authentication을 통해 로그인한 정보(아이디)를 가져와 사용할 수 있습니다.

1. 먼저 필요한 Maven을 설치합니다.

아래의 메이븐저장소에 들어가서 

mybatis, mybatis-spring, spring-jdbc, mariadb, hikaricp를 검색하여 maven을 pom.xml dependency에 추가합니다.

https://mvnrepository.com/

 

Maven Repository: Search/Browse/Explore

AWS Java SDK :: Regions Last Release on Oct 18, 2019

mvnrepository.com

예시)

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>2.0.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.3.4.RELEASE</version>
		</dependency>

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

		<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
		<dependency>
			<groupId>com.zaxxer</groupId>
			<artifactId>HikariCP</artifactId>
			<version>3.4.0</version>
		</dependency>

 

2.  webapp/WEB-INF/spring/ 에 있는 root-context.xml에 들어갑니다.

Namespaces에 들어가여 아래와 같이 체크해주고 저장합니다.

 

3. 다시 root-context에서 Source에 들어가 아래와 같이 입력해줍니다.

	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName"
			value="org.mariadb.jdbc.Driver"></property>
		<property name="jdbcUrl"
			value="jdbc:mariadb://127.0.0.1:3306/spring?useSSL=false&amp;serverTimezone=Asia/Seoul"></property>
		<property name="username" value="DB계정입력"></property>
		<property name="password" value="DB비밀번호입력"></property>
	</bean>

	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
		destroy-method="close">
		<constructor-arg ref="hikariConfig" />
	</bean> 

	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="mapperLocations"
			value="classpath:mappers/**/*.xml"></property>
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

		<property name="basePackage" value="net.test.test.dao" />
	</bean>

간단한 설명을하자면 먼저 아래의 xml 코드는 DB커넥션풀을 hikariCP를 사용하고 DB에 연결하겠다는 뜻입니다.

	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName"
			value="org.mariadb.jdbc.Driver"></property>
		<property name="jdbcUrl"
			value="jdbc:mariadb://127.0.0.1:3306/spring?useSSL=false&amp;serverTimezone=Asia/Seoul"></property>
		<property name="username" value="DB계정입력"></property>
		<property name="password" value="DB비밀번호입력"></property>
	</bean>

	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
		destroy-method="close">
		<constructor-arg ref="hikariConfig" />
	</bean> 

아래의 xml코드는 sqlSession을 연결할 수 있게하며, 데이터베이스 쿼리를 갖고있는 mapper들을 연결시켜주겠다는 의미입니다.(아래에 작성되어있음.)

<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="mapperLocations"
			value="classpath:mappers/**/*.xml"></property>
	</bean>

아래는 mapper에 작성되어있는 쿼리들을 불러오는 dao들을 스캔하는 의미입니다. value는 꼭 패키지에 맞춰 쓸 수 있도록 합니다.

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

		<property name="basePackage" value="net.test.test.dao" />
	</bean>

 

4. 아래와 같이 패키지와 controller 및 dao를 작성합니다.

임의로 작성한것입니다. 꼭 이렇게 안하셔도됩니다.

DAO파일은 인터페이스로 생성해야합니다.

 

5. 이제 쿼리를 작성할 mapper를 생성합니다. 

아래의 resources/ 폴더 밑에 mappers와 그 아래 xml 파일을 생성합니다.

xml파일에 아래와 같이입력합니다.

mapper의 namespace는 아까 작성한 TestDAO의 경로와 똑같이 해야합니다.

여기서 DB쿼리들을 작성합니다. DB접속이 잘 되었는지 확인만 하기위해 현재 시간을 나타내주는 쿼리를 작성해봅니다.

6. TestDAO를 열어 아래와 같이 TestMapper.xml에서 작성한 selectNow함수를 작성해줍니다.

그리고는 작성한 controller 에 들어갑니다.(현재 글에는 TestController입니다.)

아래와 같이 작성합니다.

MVC패턴을 이용하는 Spring에서는 아래와같이 controller에서 불러오면 안되는 것은 아니지만 패턴의 규칙이 있기때문에 controller에서 직접 불러오는 것을 추천드리지는 않지만, 테스트목적이라 여기서는 불러서 사용합니다.

 

이것을 실행하여 localhost:8080/test에 접속하면 db에서 불러온 현재 시간이 console창에  나타나는 것을 볼 수 있습니다.

1. 먼저 아래에 접속해 STS 3.9.X버전을 설치한다.

https://spring.io/tools3/sts/all

 

Spring Tool Suite™ 3 (STS 3) Download page

Use one of the links below to download an all-in-one distribution for your platform. Choose either a native installer or simple archive, they contain equivalent functionality

spring.io

그리고 최신버전 또는 옛날

버전을 설치한다.

2. 프로젝트 생성에서 MVC PROJECT를 설치한다.

3. 프로젝트의 pom.xml에 들어가 밑줄친 부분을 1.8버전, 4.3.x버전으로 변경한다

아래와 같이 변경

4. maven-compiler-plugin을 1.8버전으로 변경한다

아래와 같이 변경한다

 

전부 변경하였다면 저장해준다.

5. 프로젝트 우클릭 후 Properties를 클릭한다.

Project Facets에서 1.6으로 되어있는 Java버전을 1.8로 변경한다

Dynamic Web Module 또한 3.0으로 변경하여도 상관없으나 만약 변경한다면 프로젝트의 web.xml파일에 들어가서

web.xml 파일 상단에 web-app version="2.5" 버전을 web-app version="3.0"으로 같이 변경해준다.

6. Java Compiler 에 접속하여 버전을 1.8버전으로 변경해준다

만약 변경되어 있지 않거나 없다면 아래 사진의 파란색부분인 Java Build Path을 클릭한다.

Java Build Path에서 Add Library를 클릭해준다.

JRE System Library를 선택한다.

Installed JREs를 클릭한다.

Add를 클릭한다.

Standard VM을 선택한다.

Directory를 클릭하여 Java 1.8버전이 있는 폴더를 선택하여 Apply버튼을 눌러주어 1.8버전을 선택하고 다시 6번의 Proejct Facets에 들어가 1.8로 수정해주면 된다.

7. 프로젝트 우클릭 후 Update Project를 해준 뒤 실행해보면 잘 실행이된다.

 

참고로 pom.xml에 있는 servlet-api 버전이나, jsp, jstl 버전을 최신버전으로 변경해주어도 좋다


Spring boot 에서  Invisible reCAPTCHA 설정하는 방법이다.



reCAPTHA 는 쉽게 말해 봇이 접근을 시도하는 것으로부터 보호하여 스팸글 등록 및 자동 글 작성 자동 회원가입을 막는 것이다.


현재는 v3까지 나왔으며 여러버전이 있는 데, Invisible reCAPTCHA는 말그대로 보이지 않는다. 버튼 체크나, 그림 맞추기 등을 하지 않아도 됨.

원리는 구글측에서 공개하지는 않았지만 구글측에서 사용자의 패턴을 분석해서 방지한다는 정도로 알고있다.



1.  https://www.google.com/recaptcha/intro/v3.html 사이트에 접속한다.


우측 상단의 My reCAPTCHA에 접속한다.



2.  접속한 뒤 새로 만든다.


Label 에는 제목을 입력한다. 이 제목은 말그대로 그냥 제목이다 파일 이름 짓듯이, 프로젝트 생성하듯이 지으면 된다.

그리고 아래와 같이 기입한 후 생성한다. Send alerts to owner는 체크해도 되고 안해도된다. 그리고 만들고나서도 수정 가능하니 신경을 크게 안써도 된다.



3.  생성된 것을 확인

아래와 같이 Site key와 Secret key를 받게 된다.

Step1에는 사용방법이 간단하게 나와 있으며 

Step2에는 Invisible reCAPTCHA API에 사용에 필요한 요청과 응답이 나와 있다.


4.   https://developers.google.com/recaptcha/docs/invisible 옆의 주소에 들어간다.

구글에서 아래와 같이 기본적인 예제를 올려 놓았다. 

이것을 복사를 한다.



5. 복사를 했으면 Spring boot의 static 폴더 아래에 아래와 같이 만든다

굳이 여기가 아니더라도 프론트엔드를 따로 사용하시는 분들이라면 그 쪽에 만들어서 사용하면 된다.


data-siteKey는 3번에서 받은 Site-key를 입력한다. 그리고 action에는 reCAPTCHA에 사용할 API주소를 입력한다. 


6. action에 사용할  reCAPTCHA를 사용할 Controller를 만든다.

하지만 그 전에 reCAPTCHAP에 응답받을 DTO를 생성한다. 이 작업은 굳이 안해도 되고 String으로 바로 받아도 되지만

깔끔함을 위해 작성했다.

구글 API에 아래와 같이 나와있다. 

위를 바탕으로 DTO를 작성한다.

public class reCAPTCHA_DTO {
	private boolean success;
	private Integer number;
	private String action;
	private String challenge_ts;
	private String hostname;
	private String error_codes;
	
	
	public reCAPTCHA_DTO() {
		super();
	}


	public reCAPTCHA_DTO(boolean success, Integer number, String action, String challenge_ts, String hostname,
			String error_codes) {
		super();
		this.success = success;
		this.number = number;
		this.action = action;
		this.challenge_ts = challenge_ts;
		this.hostname = hostname;
		this.error_codes = error_codes;
	}


	public boolean isSuccess() {
		return success;
	}


	public void setSuccess(boolean success) {
		this.success = success;
	}


	public Integer getNumber() {
		return number;
	}


	public void setNumber(Integer number) {
		this.number = number;
	}


	public String getAction() {
		return action;
	}


	public void setAction(String action) {
		this.action = action;
	}


	public String getChallenge_ts() {
		return challenge_ts;
	}


	public void setChallenge_ts(String challenge_ts) {
		this.challenge_ts = challenge_ts;
	}


	public String getHostname() {
		return hostname;
	}


	public void setHostname(String hostname) {
		this.hostname = hostname;
	}


	public String getError_codes() {
		return error_codes;
	}


	public void setError_codes(String error_codes) {
		this.error_codes = error_codes;
	}
}

7. 이제 controller를 작성한다.


params 의 seceret에서는 3번의 seceret_key를 적는다.

3번에의 요청에서 봤듯이 ip가 필요하기 때문에 ip를 받아온다. (ip받아오는 방법은 서버마다 다르기 때문에 굳이 이렇게 안해도 됨.)

g-recaptha-response역시 3번에 나와 있듯이 구글측에서 주는 것이기 때문에 RequsetParam으로 받아 그대로 사용하면 된다.

그리고 아래와 같이 작성해서 post를 날리면 된다.


@PostMapping() public reCAPTCHA_DTO reCAPTCHA_TEST(@RequestParam(name="g-recaptcha-response") String recaptchaResponse , HttpServletRequest request) { String ip = request.getRemoteAddr(); String url = "https://www.google.com/recaptcha/api/siteverify"; String params="?secret=6LcwQYIUAAA******************&response="+recaptchaResponse; RestTemplate restTemplate = new RestTemplate(); reCAPTCHA_DTO re = restTemplate.exchange(url+params, HttpMethod.POST, null, reCAPTCHA_DTO.class).getBody(); if(re.isSuccess()) { System.out.println("성공"); } else { System.out.println("실패"); } return re; }

8. 결과


아래 사진과 같이 맨 오른쪽 하단에 reCAPTCHA 표시가 나타나며 submit을 누르면 결과가나온다.

결과



Invisible reCAPTCHA말고도 다른 reCAPTCHA사용하는 방법 역시 위와 크게 다르지 않기 때문에 아래의 레퍼런스에서 확인하여 때에 맞게 사용하면 된다.



참고 -  https://developers.google.com/recaptcha/intro


마지막으로 hashmap 을 json으로 만드는 방법과, JsonObject를 생성하는 방법이다.



Spring boot Json 1편, 2편, 3편, 4편

1. 2018/11/06 - [Spring Boot] - Spring Boot Json, JsonObject로 만들기 - JSON 1편

2. 2018/11/07 - [Develop/Spring Boot] - Spring Boot Json, Gson을 이용한 JsonObject to String, String to JsonObject- JSON 2편

3. 2018/11/09 - [Develop/Spring Boot] - Spring Boot Json, Jackson을 이용한 JsonParsing - Json 3편

4. 2018/11/12 - [Develop/Spring Boot] - Spring Boot Deserialization Json, Deserialization JsonString to JsonObject - Json 4편



번외 Database의 값을 Json으로 select하는 방법.

1. 2018/10/24 - [Spring Boot] - Spring boot jpa map, hashmap, JSON형식

2. 2018/10/28 - [Spring Boot] - Spring boot JPA EntityManager를 이용한 Map형식으로 mapping하기


Spring boot에서 MySQL JSON 타입 SELECT하는 방법

1. 2018/11/30 - [Develop/Spring Boot] - Spring boot MySQL JSON - MySQL JSON DATA TYPE 값 가져오기



HashMap을 Json으로 만드는 방법을 배우기에 앞서 JsonObject를 생성하는 방법을 먼저 본다.


1. google-json-simple을 이용한 JsonObject 만드는 방법.


xml에 아래와 같은 dependency를 추가한다.


		com.googlecode.json-simple
		json-simple
		1.1


우리가 만들어볼 Json예제는 4편에서 사용한 Json이다.


{
    "id": 1,
    "password": "1234",
    "details": [
        {
            "name": "test",
            "age": 20
        },{
            "name": "test2",
            "age": 21
        }
    ] 
}

그리고 아래와 같이 JSONObject라는 것과 JSONArray라는 것을 사용하여 JSON을 생성할 수 있다.


public void test() {
		JSONObject obj = new JSONObject();
		JSONArray arr = new JSONArray();
		
		obj.put("id", 1);
		obj.put("password", "1234");
		
		JSONObject obj2 =new JSONObject();
		obj2.put("name", "test");
		obj2.put("age", 20);
		
		arr.add(obj2);
		
		obj2 = new JSONObject();
		obj2.put("name", "test2");
		obj2.put("age", 21);
		
		arr.add(obj2);
		
		obj.put("details", arr);
		
		System.out.println(obj.toString());
		
}




현재는 Json이 Array를 포함하여 JSONArray를 사용하였지만 일반 적인 key : value 형태는 JSONObject 하나만으로도 생성할 수 있다.


2. Gson을 이용한JsonObject 생성


이 방법은 Json  2편에서 배웠으나 이번엔 Array를 사용하기 때문에 다시 한번 해본다. 사실 위의 json-simple과 별반 다를게 없다.



	public void test() {
		Gson gson = new Gson();
		JsonObject obj = new JsonObject();
		JsonArray arr = new JsonArray();
		
		obj.addProperty("id", 1);
		obj.addProperty("password", "1234");
		
		JsonObject obj2 = new JsonObject();
		obj2.addProperty("name", "test");
		obj2.addProperty("age", 20);
		arr.add(obj2);
		
		obj2= new JsonObject();
		obj2.addProperty("name", "test2");
		obj2.addProperty("age", 21);
		
		arr.add(obj2);
		
		obj.add("details", arr);
		
		String jsonString = obj.toString();
		
		System.out.println("gson을 이용한 객체생성");
		System.out.println(jsonString);
		
	}




3. HashMap을 Json으로 만드는 방법.


HashMap<String, Object>를 선언해서 이번 편에서 했던 모든 것들(json-simple의 obj와 gson의 obj)을 HashMap에 put해보고

일반 데이터를 HashMap에 put해서 json으로 변환해 보는 법을 해본다. 그리고 gson의 prettyprinting을 이용하여 예쁘게 출력해본다.



public void test() {
		JSONObject obj = new JSONObject();
		JSONArray arr = new JSONArray();

		obj.put("id", 1);
		obj.put("password", "1234");

		JSONObject obj2 = new JSONObject();
		obj2.put("name", "test");
		obj2.put("age", 20);

		arr.add(obj2);

		obj2 = new JSONObject();
		obj2.put("name", "test2");
		obj2.put("age", 21);

		arr.add(obj2);

		obj.put("details", arr);

		
		JsonObject g_obj = new JsonObject();
		JsonArray g_arr = new JsonArray();

		g_obj.addProperty("id", 1);
		g_obj.addProperty("password", "1234");

		JsonObject g_obj2 = new JsonObject();
		g_obj2.addProperty("name", "test");
		g_obj2.addProperty("age", 20);
		g_arr.add(g_obj2);

		g_obj2 = new JsonObject();
		g_obj2.addProperty("name", "test2");
		g_obj2.addProperty("age", 21);

		g_arr.add(g_obj2);

		g_obj.add("details", g_arr);
		
		HashMap map = new HashMap();
		map.put("json-simple", obj);
		map.put("gson", g_obj);
		map.put("HashMap", "맵테스트");
		map.put("숫자테스트", 1234567890);
		
		Gson gson = new GsonBuilder().setPrettyPrinting().create();
		String jsonString = gson.toJson(map, new TypeToken>() {
		}.getType());
		System.out.println("HashMap to JSON");
		System.out.println(jsonString);

	}



이로써 Spring boot 에서의 Json에 대한 학습을 마무리한다.

1편부터 마지막편까지의 내용과 번외편 내용 2개만 알아도 Spring boot에서 모든 데이터들을 Json으로 만들 수 있다.


어찌보면 가장 중요한 Deserialization한 JsonString 형태를 파싱하는 방법이다.

Spring Boot에서 Deserialization 파싱을 위해 Jackson과 gson을 사용하면서 동시에 클래스를 생성하여 사용해야한다.



Spring boot Json 1편, 2편, 3편, 마지막

1. 2018/11/06 - [Spring Boot] - Spring Boot Json, JsonObject로 만들기 - JSON 1편

2. 2018/11/07 - [Develop/Spring Boot] - Spring Boot Json, Gson을 이용한 JsonObject to String, String to JsonObject- JSON 2편

3. 2018/11/09 - [Develop/Spring Boot] - Spring Boot Json, Jackson을 이용한 JsonParsing - Json 3편

4. 2018/11/13 - [Develop/Spring Boot] - Spring Boot Json, hashmap to json , JsonObject 만들기- JSON 마지막



번외 Database의 값을 Json으로 select하는 방법.

1. 2018/10/24 - [Spring Boot] - Spring boot jpa map, hashmap, JSON형식

2. 2018/10/28 - [Spring Boot] - Spring boot JPA EntityManager를 이용한 Map형식으로 mapping하기


Spring boot에서 MySQL JSON 타입 SELECT하는 방법

1. 2018/11/30 - [Develop/Spring Boot] - Spring boot MySQL JSON - MySQL JSON DATA TYPE 값 가져오기



1. Class를 생성하여 Gson을 이용한 Deserializaion한 JsonString to Object(JsonObject)


앞의 1편, 2편, 3편에 사용했던 TestDTO를 수정하자.


수정하기 전 먼저 Test_2DTO를 새로 생성한다


public class Test_2DTO {
	private String name;
	private int age;
	
	public Test_2DTO() {
		super();
	}

	public Test_2DTO(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}
public class TestDTO {

	private Integer id;
	private String password;
	private List details;
	
	
	public TestDTO() {
		super();
	}


	public TestDTO(Integer id, String password, List details) {
		super();
		this.id = id;
		this.password = password;
		this.details = details;
	}


	public Integer getId() {
		return id;
	}


	public void setId(Integer id) {
		this.id = id;
	}


	public String getPassword() {
		return password;
	}


	public void setPassword(String password) {
		this.password = password;
	}


	public List getDetails() {
		return details;
	}


	public void setDetails(List details) {
		this.details = details;
	}


	@Override
	public String toString() {
		return new Gson().toJson(this);
	}
}


생성했다면, 


public void test() {
		
		String jsonString = "{\r\n" + 
				"    \"id\": 1,\r\n" + 
				"    \"password\": \"1234\",\r\n" + 
				"    \"details\": [\r\n" + 
				"        {\r\n" + 
				"            \"name\": \"test\",\r\n" + 
				"            \"age\": 20\r\n" + 
				"        },{\r\n" + 
				"            \"name\": \"test2\",\r\n" + 
				"            \"age\": 21\r\n" + 
				"        }\r\n" + 
				"    ] \r\n" + 
				"}";
		Gson gson = new Gson();
		TestDTO t = gson.fromJson(jsonString, TestDTO.class);
		System.out.println("id : " +t.getId());
		System.out.println("password : "+t.getPassword());
		System.out.println("name1 : "+t.getDetails().get(0).getName());
		System.out.println("age1: "+t.getDetails().get(0).getAge());
		System.out.println("name2 : "+t.getDetails().get(1).getName());
		System.out.println("age2: "+t.getDetails().get(1).getAge());
		
	}

위에 사용한 Json내용이다., 


{
    "id": 1,
    "password": "1234",
    "details": [
        {
            "name": "test",
            "age": 20
        },{
            "name": "test2",
            "age": 21
        }
    ] 
}


위 test() 메소드를 실행하면 아래와 같이 Deserializaion한 JsonString이 파싱되어 JsonObject에 알맞게 들어간다.



2. Jackson의 ObjectMapper를 이용한 Json String to JsonObject 이다.


Json내용은 위와 동일한 상태에서 진행하였다.


public void test() {
		ObjectMapper objectMapper = new ObjectMapper();
		 
		String jsonString = "{\r\n" + 
				"    \"id\": 1,\r\n" + 
				"    \"password\": \"1234\",\r\n" + 
				"    \"details\": [\r\n" + 
				"        {\r\n" + 
				"            \"name\": \"test\",\r\n" + 
				"            \"age\": 20\r\n" + 
				"        },{\r\n" + 
				"            \"name\": \"test2\",\r\n" + 
				"            \"age\": 21\r\n" + 
				"        }\r\n" + 
				"    ] \r\n" + 
				"}";
		  try {
	            TestDTO t = objectMapper.readValue(jsonString, TestDTO.class);    // String to Object로 변환
	            System.out.println("ObjectMapper테스트");
	    		System.out.println("id : " +t.getId());
	    		System.out.println("password : "+t.getPassword());
	    		System.out.println("name1 : "+t.getDetails().get(0).getName());
	    		System.out.println("age1: "+t.getDetails().get(0).getAge());
	    		System.out.println("name2 : "+t.getDetails().get(1).getName());
	    		System.out.println("age2: "+t.getDetails().get(1).getAge());	     
	
	        } catch (IOException e) {
	            e.printStackTrace();
	        }		
}

gson과 마찬가지로 잘 작동된다.


3. Jackson JsonNode 를 이용한 Deserializaion String to JsonObject


어떻게 보면 가장 핵심인 부분일 수도 있다. 클래스 생성없이 할 수 있다는 큰 장점이있다.


Deserializaion Json Data는 위와 동일한 데이터를 사용한다.



public void test() {
		ObjectMapper objectMapper = new ObjectMapper();

		String jsonString = "{\r\n" + "    \"id\": 1,\r\n" + "    \"password\": \"1234\",\r\n"
				+ "    \"details\": [\r\n" + "        {\r\n" + "            \"name\": \"test\",\r\n"
				+ "            \"age\": 20\r\n" + "        },{\r\n" + "            \"name\": \"test2\",\r\n"
				+ "            \"age\": 21\r\n" + "        }\r\n" + "    ] \r\n" + "}";
		try {
			System.out.println("Jackson JsonNode 테스트");
			JsonNode t = objectMapper.readValue(jsonString, JsonNode.class); // String to Object로 변환
			
			JsonNode id = t.get("id");
			System.out.println("id : " + id.asInt());
			
			JsonNode password = t.get("password");
			System.out.println("password : " + password.asText());
			
			JsonNode details = t.get("details");
			JsonNode details_1 = details.get(0);		
			System.out.println("name1 : " + details_1.get("name").asText());
			System.out.println("age1: " + details_1.get("age").asInt());
			
			JsonNode details_2 = details.get(1);	
			System.out.println("name2 : " + details_2.get("name").asText());
			System.out.println("age2: " + details_2.get("name").asText());

		} catch (IOException e) {
			e.printStackTrace();
		}
}

class 생성없이 파싱이 잘 되었다


이 처럼 웬만한 것들은 class를 생성하여 모든 Deserializaion을 파싱할 수 있으며,

Jackson JsonNode 를 이용하여 처리할 수 있다. 


Spring Boot에서 Json 파싱을 위해 Jackson을 기본적으로 제공해준다. Spring에서는 maven 또는 gradle을 xml에 추가해야한다.

사실 기본적인 기능은 앞선 gson과 다를게 없다.


Spring boot Json 1편, 2편, 4편, 마지막

1. 2018/11/06 - [Spring Boot] - Spring Boot Json, JsonObject로 만들기 - JSON 1편

2. 2018/11/07 - [Develop/Spring Boot] - Spring Boot Json, Gson을 이용한 JsonObject to String, String to JsonObject- JSON 2편

3. 2018/11/12 - [Develop/Spring Boot] - Spring Boot Deserialization Json, Deserialization JsonString to JsonObject - Json 4편

4. 2018/11/13 - [Develop/Spring Boot] - Spring Boot Json, hashmap to json , JsonObject 만들기- JSON 마지막




번외 Database의 값을 Json으로 select하는 방법.

1. 2018/10/24 - [Spring Boot] - Spring boot jpa map, hashmap, JSON형식

2. 2018/10/28 - [Spring Boot] - Spring boot JPA EntityManager를 이용한 Map형식으로 mapping하기


Spring boot에서 MySQL JSON 타입 SELECT하는 방법

1. 2018/11/30 - [Develop/Spring Boot] - Spring boot MySQL JSON - MySQL JSON DATA TYPE 값 가져오기



1. Jackson ObjectMapper (JsonString to Object)


public void test() {
		ObjectMapper objectMapper = new ObjectMapper();

		String Json =
		    "{ \"id\" : 1, \"password\" : \"1234\" }";

		try {
		    TestDTO t = objectMapper.readValue(Json, TestDTO.class);	// String to Object로 변환

		    System.out.println("id = " + t.getId());
		    System.out.println("password = " + t.getPassword());
		    
		    String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(t); //다시 jsonString으로 변환
		    System.out.println(jsonString);
		} catch (IOException e) {
		    e.printStackTrace();
		}
}


(위의 TestDTO은 1편에 나와있다.)


objectMapper를 통해 JsonString을 Object로 변환할 수 있었고 writeValueAsString을 통해 다시 JsonString으로도 변환이 가능하다


2. Object From JsonFile



ObjectMapper objectMapper = new ObjectMapper();

URL url = new URL("file:data/test.json");

TestDTO t = objectMapper.readValue(url, TestDTO.class);


test.json 파일엔

{

"id" : 1,

"password" : 1234

}

들어 가있다.



기본적인 사용방법은 여기까지이다 다음편에 Jackson JsonNodeClass를 설명한다.

Jackson 가이드 - https://www.baeldung.com/jackson


1편에서 Spring Boot에서 데이터를 JSON형식으로 표현하는 가장 기본적인 방법인 클래스를 이용한 방법을 배웠다.

이번에는 Gson을 이용한 JsonOjbect to String, String to JsonObject를 알아아보자.


개인적인 경험으론 Gson이 가장 Json파싱에서 핵심이 아닐까 생각한다.



Spring boot Json 1편, 3편, 4편, 마지막

1. 2018/11/06 - [Spring Boot] - Spring Boot Json, JsonObject로 만들기 - JSON 1편

2 .2018/11/09 - [Develop/Spring Boot] - Spring Boot Json, Jackson을 이용한 JsonParsing - Json 3편

3. 2018/11/12 - [Develop/Spring Boot] - Spring Boot Deserialization Json, Deserialization JsonString to JsonObject - Json 4편

4. 2018/11/13 - [Develop/Spring Boot] - Spring Boot Json, hashmap to json , JsonObject 만들기- JSON 마지막



번외 Database의 값을 Json으로 select하는 방법.

1. 2018/10/24 - [Spring Boot] - Spring boot jpa map, hashmap, JSON형식

2. 2018/10/28 - [Spring Boot] - Spring boot JPA EntityManager를 이용한 Map형식으로 mapping하기


Spring boot에서 MySQL JSON 타입 SELECT하는 방법

1. 2018/11/30 - [Develop/Spring Boot] - Spring boot MySQL JSON - MySQL JSON DATA TYPE 값 가져오기




1. 먼저 pom.xml에 의존성을 추가한다.



		com.google.code.gson
		gson
		2.8.5


2. Gson을 이용한 Json 생성


public String test3() {
		
		Gson gson = new Gson();
		JsonObject obj = new JsonObject();
		String id=null;
		obj.addProperty("id", id);
		obj.addProperty("pass", 1234);
		
		String i = obj.toString();
		String j = gson.toJson(obj);
		System.out.println(i);
		System.out.println(j);
		return i;
}


Gson의 JsonObject를 Import받고 JsonObject를 이용하여 Json 형식으로 만들었다.

위의 toString()으로 호출한 결과와 gson.toJson()을 이용한 결과가 다르다는 걸 볼 수 있다.

아래의 gson.toJson()을 이용하면 null값이 들어올 경우 키값이 사라져 버린다.


3. String to JsonObject


public void test3() {
		
		Gson gson = new Gson();
		String json = "{\"id\": 1, \"password\": \"1234\"}";

		TestDTO test = gson.fromJson(json, TestDTO.class);
		System.out.println(test.getId());
		System.out.println(test.getPassword());
		
}


1편에서 사용한 TestDTO를 통해 Json객체를 생성할 수 있다.


4.  객체를 Json으로 만들기


	public void test3() {
		
		Gson gson = new Gson();
		TestDTO test2 = new TestDTO();
		test2.setId(2);
		test2.setPassword("2222");
		String i=gson.toJson(test2);
		System.out.println(i);
	}


5.  Gson의 JsonParser와 JsonElement를 통한 JsonParsing


	public void test3() {
		
		String json = "{\"id\": 1, \"password\": \"1234\"}";
		JsonParser jp = new JsonParser();
		JsonElement je = jp.parse(json);
		int id = je.getAsJsonObject().get("id").getAsInt();
		String pass = je.getAsJsonObject().get("password").getAsString();
		System.out.println(id + " / " + pass);
	}


6. Gson을 이용하여 Class의 toString() 을 이용한 Json 생성


1편의 TestDTO클래스에 Gson을 이용한 toString() 으로 보다 빠르고 편리하게 Json을 생성할 수 있다.


import com.google.gson.Gson;

public class TestDTO {

	private Integer id;
	private String password;
	
	
	public TestDTO() {
		super();
	}
	public TestDTO(Integer id, String password) {
		super();
		this.id = id;
		this.password = password;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
	@Override
	public String toString() {
		return new Gson().toJson(this);
	}
}

	public void test3() {

		Gson gson = new Gson();
		TestDTO test2 = new TestDTO();
		test2.setId(2);
		test2.setPassword("2222");
		String json = test2.toString();
		System.out.println(json);
	}


7. 기타


이외에도 Json 예쁘게 출력하는 방법 등 여러가지 기능이 존재한다.



Gson가이드 - https://github.com/google/gson/blob/master/UserGuide.md


Spring Boot 에서 TimeZone 설정하려면 아래와 같이 @PostConStruct를 설정해주면 된다.


@SpringBootApplication
public class Application {

	@PostConstruct
	void started() {
		TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
	}

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);

	}

}


UTC를 원한다면 TimeZone.getTimeZone("UTC")라고 하면 된다.


시간을 KST로 설정하고싶어서 TimeZone.getTimeZone("KST")라고 계속 했는데 안되서 삽질한 경험이 있다. KST라고하면 안되고

한국 시간 설정은 Asia/Seoul로 설정해주면 된다.


그 외 example timezone offset은 아래의 사이트에서 확인할 수 있다.

https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

+ Recent posts