JSP 파일에서 한글만 깨지는데 Server에서 받아온 데이터는 이상이 없고 유독 JSP 에서 작성한 글만 깨지는 현상이 발생 했습니다.

 

 

일반적인 방법으로 해결 방법은

 

1. JSP 페이지 상단에 다음을 입력하면 해결이 됩니다.

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

 

2. 이도 아니면 UTF-8EUC-KR로 변경하면 해결이 되기도 합니다.

 

3. 아니면 JSP 문서를 꼭 찍어서 UTF-8로 변환 합니다.

   파일에 마우스올리고 우클릭하여 properties 선택 합니다.

 

 

 

4. 그래도 안되면 Text Editor(메모장, EditPlus, UltraEditor...)에서 UTF-8로 변경해서 가지고 옵니다.

 

5. 햐! 이것도 아니면 eclipse, spring boot의 설정이 잘못되었을 수 있습니다.

   여러 설정을 알아듣지 못하는건 툴 자체의 설정에 문제가 있는것 같습니다.

 

   Window > Preferences 메뉴를 클릭 합니다.

 

 

좌측에서 General > Content Types를 클릭 하고

우측에서 Text 를 확장 합니다.

 

 

확장한 Text 에서 하단으로 내려오면 JSP가 있습니다.

여기서 하단 Default encodingUTF-8로 입력하고 JSPUTF-8로 다시 원복.

하단 [Apply and Close] 버튼을 클릭하고 다시 실행을 하면

 

한글이 잘 나옵니다.

 

또 무슨 방법이 있을까요?

 

- copy coding -

스프링 부트에서 내장된 tomcat이 아닌 외부 톰캣이나 기타 WAS를 이용하여 서비스를 하려면 프로젝트를 war로 배포해야 합니다.  배포 방법은 간단 합니다.

오늘은 몇일 전에 설치한 JEUS에 배포를 해보려고 하는데 작업 순서는

 

1. build.gradlewar 추가 및 내장 톰캣 종속 제거

2. ApplicationSpringBootServletInitializer 상속 수정

3. WAR 생성

4. JEUS 배포

5. 배포 오류

 

이고 Jeus 설치는 https://copycoding.tistory.com/388 을 참고하면 됩니다.

 

1. build.gradlewar 추가

 

먼저 Spring Boot에서 war를 생성할 수 있도록 build.gradle에 한줄 추가해 줍니다.

 

id 'war'

 

그리고 내장 tomcat WAR 추가되지 않도록 한줄 더 추가 합니다.

 

providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

 

수정된 build.gradle 모습은

plugins {
        id 'org.springframework.boot' version '2.5.6'
        id 'io.spring.dependency-management' version '1.0.11.RELEASE'
        id 'java'
        id 'war'
}
 
dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
       
        providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

 

내장 tomcat을 제거하지 않으면 배포 중 오류가 발생하는 상황은 맨 끝에 소개합니다.

 

 

2. ApplicationSpringBootServletInitializer 상속 수정

 

그리고 외부 WAS를 사용하기 위해 Context를 등록해야 하는데 예전에는 web.xmlapplication context를 등록 했지만 servlet 3.0부터 SpringBootServletInitializer를 상속 받아 사용할 수 있도록 되었습니다.

 

@SpringBootApplication
public class DemoApplication {
 
        public static void main(String[] args) {
               SpringApplication.run(DemoApplication.class, args);
        }
 
}

 

기존 소스에 SpringBootServletInitializer 상속 받고 override를 해주면 됩니다.

 

configure가 보이는 군요.  클릭하고 [OK] 해서 추가해주고

 

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
 
        public static void main(String[] args) {
               SpringApplication.run(DemoApplication.class, args);
        }
 
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
               // TODO Auto-generated method stub
               return builder.sources(DemoApplication.class);
        }
}

 

return 값을 수정해 줍니다. 그냥 다 손으로 입력해도 됩니다.

 

 

3. WAR 생성

 

이제 Spring Boot에서 war를 생성 합니다.

 

Gradle Tasks에서 build 또는 war 를 더블 클릭해 줍니다.

 

Gradle Executions에 진행상황을 보여줍니다.  프로젝트를 빌드하다보면 test 소스 빌드에서 빨간색 오류가 나타나기도 하지만 무시해도 됩니다.  

 

Duration 숫자가 멈추고 완료되면 프로젝트의 build > libs 폴더에 가면 war 파일이 보입니다.

 

이제 Jeus를 실행해서 배포 준비를 합니다.

 

 

4. JEUS 배포

 

제우스 admin 화면 좌측 메뉴에서 [Servers]를 선택하여 서버들을 확인 합니다.

 

배포할 서버가 살아있는지 확인을 합니다. server1에 배포를 하려고 하는데 잘 살아있군요.

 

좌측 메뉴에서 [Applications] 메뉴를 클릭 합니다.

 

여기서 상단 회색 버튼 중 [deploy]를 클릭 하면 배포 설정 화면이 나옵니다.

 

id를 입력해 주고 path에서 [입력] 버튼을 클릭 하면 팝업 창이 하나 나오는데

 

deploy하려는 파일을 선택해 줍니다.  Type, Target Server 등은 위에 있는 이미지를 확인해서 설정 합니다. (지금보니 server1shutdown이네요. 실행전에 캡쳐한거라...)

 

아랫 부분에 있는 고급 선택사항에서는 Context Path만 입력 합니다.

 

여기에 입력하는 내용이 나중에 웹을 실행할때 영향을 주게 됩니다. 저는 프로젝트를 구분하려고/demo로 입력 했는데 그냥 /만 입력해도 됩니다.

 

이제 [확인] 버튼을 클릭하면 오류가 발생하던가 배포가 잘 되던가 하겠지요.

 

저는 배포가 잘 완료 되었습니다.

웹에서 접속을 해보려면 몇번 포트를 사용하고 있는지 확인을 해봐야하니 server1을 열어봅니다.

 

좌측 메뉴에서 [Servers]를 선택 하고

 

우축에서 server1을 클릭 하고

 

탭메뉴에서 [Resource]를 클릭해 보면 8088로 서비스가 되고 있군요.

 

 

몇일전에 글을 올린 STS4관련 프로젝트를 배포한것이니 http://localhost:8088/api/test하면 될것 같지만 배포할 때 [고급선택 사양]에서 /demopath를 잡았기 때문에 /demo를 추가해 주어야 합니다.

 

http://localhost:8088/demo/api/test

 

JEUS 8에도 배포가 잘 되었습니다.

 

 

5. 배포 오류

 

Spring Boot에서 war 를 만들어 배포할때 가장 많이 발생하는 오류입니다.

 

 

오류 로그를 보면

D:\TmaxSoft\JEUS8\domains\jeus_domain\servers\server1
\.workspace\deployed\demo\demo-0_0_1-SNAPSHOT-plain_war___\
WEB-INF\lib\tomcat-embed-core-9.0.54.jar
JAR file was not loaded because the class
javax/servlet/Servlet.class violated Servlet Spec 3.1.

 

tomcat-embed-core1번에서 설명한것 처럼 꼭 제거를 해주어야 jeus에 배포시 오류가 발생하지 않습니다.  외부 Tomcat에서는 오류가 발생하지 않는데 jeus에서는 오류가 나옵니다.

 

- copy coding -


Spring Boot에서 프로젝트를 생성하여 Firestore에 있는 데이터 작업을 하려고 합니다.  


Firestore spring boot crud


Firebase에는 다음과 같이 collection을 만들어서 데이터를 입력 하였습니다.


Firestore spring boot crud


이 데이터베이스에 데이터를 조회, 추가, 수정, 삭제하는 기능을 Spring Boot를 이용하여 만들어 보려고 합니다.

 

Spring Boot에서 Spring Starter Project를 선택하여 신규 프로젝트를 생성 합니다.


Firestore spring boot crud


입력 사항은 테스트이니까 대충 적어 넣고 Next 버튼을 클릭 합니다.


Firestore spring boot crud


 

DependencySpring Web만 추가 했습니다.  Finish 버튼을 클릭 합니다.

 

pom.xmlfirebase를 추가 합니다현재 6.13.x 버전까지 나와있는데 한 단계 낮추어서 적어봤습니다.

 

               <dependency>

                   <groupId>com.google.firebase</groupId>

                   <artifactId>firebase-admin</artifactId>

                   <version>6.12.1</version>

                </dependency>

 

Firebase의 필드에 해당하는 Vo를 생성 합니다.

 

package com.copycoding.firebase;

 

public class Member {

        String id;

        String name;

        int age;

        String tel;

       

        public String getId() {

               return id;

        }

        public void setId(String id) {

               this.id = id;

        }

        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 String getTel() {

               return tel;

        }

        public void setTel(String tel) {

               this.tel = tel;

        }

}

 

 

Service를 생성하기 위해 먼저 Interface 파일을 생성하고

 

package com.copycoding.firebase;

 

public interface FirebaseService {

 

        public insertMember(Member member) throws Exception;

       

        public Member getMemberDetail(String id) throws Exception;

       

        public String updateMember(Member member) throws Exception;

       

        public string deleteMember(String id) throws Exception;

}

 

 

 

Service Implement도 작성 합니다.

 

package com.copycoding.firebase;

 

import org.springframework.stereotype.Service;

 

import com.google.api.core.ApiFuture;

import com.google.cloud.firestore.DocumentReference;

import com.google.cloud.firestore.DocumentSnapshot;

import com.google.cloud.firestore.Firestore;

import com.google.cloud.firestore.WriteResult;

import com.google.firebase.cloud.FirestoreClient;

 

@Service

public class FirebaseServiceImpl implements FirebaseService {

 

        public static final String COLLECTION_NAME="member";

       

        @Override

        public String insertMember(Member member) throws Exception {

               Firestore firestore = FirestoreClient.getFirestore();

               ApiFuture<WriteResult> apiFuture = firestore.collection(COLLECTION_NAME).document(member.getId()).set(member);

               return apiFuture.get().getUpdateTime().toString();

        }

 

        @Override

        public Member getMemberDetail(String id) throws Exception {

               Firestore firestore = FirestoreClient.getFirestore();

               DocumentReference documentReference = firestore.collection(COLLECTION_NAME).document(id);

               ApiFuture<DocumentSnapshot> apiFuture = documentReference.get();

               DocumentSnapshot documentSnapshot = apiFuture.get();

               Member member = null;

               if(documentSnapshot.exists()) {

                       member = documentSnapshot.toObject(Member.class);

                       return member;

               } else {

                       return null;

               }

        }

 

        @Override

        public String updateMember(Member member) throws Exception {

               Firestore firestore = FirestoreClient.getFirestore();

               ApiFuture<WriteResult> apiFuture = firestore.collection(COLLECTION_NAME).document(member.getId()).set(member);

               return apiFuture.get().getUpdateTime().toString();

        }

 

        @Override

        public String deleteMember(String id) throws Exception {

               Firestore firestore = FirestoreClient.getFirestore();

               ApiFuture<WriteResult> apiFuture = firestore.collection(COLLECTION_NAME).document(id).delete();

              

               return "Document id :" + id + " delete";

        }

}

 

 

 

이제 마지막으로 Controller Rest Api 형식으로 작성 합니다.

 

package com.copycoding.firebase;

 

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

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

 

@RestController

public class FirebaseController {

 

        @Autowired

        FirebaseService firebaseService;

       

        @GetMapping("/insertMember")

        public String insertMember(@RequestParam Member member) throws Exception {

               return firebaseService.insertMember(member);

        }

       

        @GetMapping("/getMemberDetail")

        public Member getMemberDetail(@RequestParam String id) throws Exception {

               return firebaseService.getMemberDetail(id);

        }

       

        @GetMapping("/updateMember")

        public String updateMember(@RequestParam Member member) throws Exception {

               return firebaseService.updateMember(member);

        }

       

        @GetMapping("/deleteMember")

        public String deleteMember(@RequestParam String id) throws Exception {

               return firebaseService.deleteMember(id);

        }

}

 

여기 까지는 일반 프로젝트와 동일한 방식으로 작성을 하면 됩니다.

 

package com.copycoding.firebase;

 

import java.io.FileInputStream;

import javax.annotation.PostConstruct;

import org.springframework.stereotype.Service;

import com.google.auth.oauth2.GoogleCredentials;

import com.google.firebase.FirebaseApp;

import com.google.firebase.FirebaseOptions;

 

@Service

public class FirebaseInitialize {

 

        @PostConstruct

    public void initialize() {

        try {

        FileInputStream serviceAccount =

                  new FileInputStream("./copycodingServiceAccount.json");

 

                FirebaseOptions options = new FirebaseOptions.Builder()

                  .setCredentials(GoogleCredentials.fromStream(serviceAccount))

                  .setDatabaseUrl("https://copycoding-bca04.firebaseio.com")

                  .build();

 

                FirebaseApp.initializeApp(options);

            } catch (Exception e) {

                e.printStackTrace();

            }

       

        }

}

 

추가로 Firebase에 접속하기 위한 설정 파일을 하나 생성해주면 됩니다.

이렇게 해서 프로그램이 완성 되었습니다.


이제 테스트를 해 봅니다.

귀찮으니 조회만 해 봅니다.


Firestore spring boot crud


조회가 잘 되는 군요.

성의가 없는 것 같아 삭제도 해 봅니다.


Firestore spring boot crud


삭제가 되었다고 하는데 Firebase 데이터베이스에 들어가 확인해 봅니다.


Firestore spring boot crud


document 2번이 삭제 되어 있습니다이런 식으로 작업을 하면 됩니다.


- copy coding -


예전에 Quartz를 이용해서 작업할 때 보다는 @Scheduled annotation을 사용하면 배치 작업을 무척 쉽게 만들 수 있습니다.


spring boot Scheduler @Scheduled batch


얼마나 간단하고 쉬운지 한번 만들어 보겠습니다.


spring boot Scheduler @Scheduled batch


먼저 프로젝트를 하나 생성 합니다.


spring boot Scheduler @Scheduled batch


프로젝트 이름을 대충 적어주고


spring boot Scheduler @Scheduled batch


 

화면을 만들건 아니지만 일단 Web을 추가해서 생성 합니다.

 

이제 설정을 해줍니다.


Application 메인 파일을 열고

package com.copycoding.batch;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.scheduling.annotation.EnableScheduling;

 

@SpringBootApplication

@EnableScheduling

public class BatchApplication {

 

        public static void main(String[] args) {

               SpringApplication.run(BatchApplication.class, args);

        }

}

 

@EnableScheduling 어노테이션을 추가해 줍니다.

 

그리고 실제 스케쥴 작업할 class 파일을 만듭니다.

 

package com.copycoding.batch;

 

import java.time.LocalDateTime;

 

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;

 

@Component

public class ScheduleTask {

 

@Scheduled(fixedDelay = 2000)

public void task1() {

        System.out.println("The current date (1) : " + LocalDateTime.now());

}

       

@Scheduled(fixedDelayString = "${spring.task.fixedDelay}")

public void task2() {

        System.out.println("The current date (2) : " + LocalDateTime.now());

}}

 

중요한건 class 파일에 @Component를 설정해야 합니다이렇게 두개의 어노테이션을 적어주기만 하면 설정은 끝입니다.

이제 메소드를 만들고 @Scheduled를 이용해서 메소드의 작동 시간을 입력하고 코딩을 해줍니다위에 있는 프로그램을 실행하면


spring boot Scheduler @Scheduled batch


 

이런식으로 결과를 얻을 수 있습니다.  annotation만으로 쉽게 배치 작업이 완료 됩니다.

 

@Scheduled() 어노테이션에 들어가는 설정들을 정리해 보았습니다.

 

fixedDelay

@Scheduled(fixedDelay = 1000)

이전 작업이 종료된 후 설정시간(밀리터리세컨드) 이후에 다시 시작

fixedDelayString

@Scheduled(fixedDelay = “1000”)

fixedDelay와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

fixedRate

@Scheduled(fixedRate = 1000)

설정된 시간마다 시작을 한다. 즉 이전 작업이 종료되지 않아도 시작.

fixedRateString

@Scheduled(fixedRateString = “1000”)

fixedRate와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

initialDelay

@Scheduled(fixedRate = 5000, initialDelay = 3000)

프로그램이 시작하자마자 작업하는게 아닌 시작을 설정된 시간만큼 지연하여 작동을 시작 한다.(예제는 3초 후 부터 5초 간격으로 작업)

initialDelayString

@Scheduled(fixedRate = 5000, initialDelay = “3000”)

initialDelay와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

cron

@Scheduled(cron = "* * * * * *")

첫번째 부터 위치별 설정 값은

(0-59)

(0-59)

시간(0-23)

(1-31)

(1-12)

요일(0-7)

zone

@Scheduled(cron = "0 0 14 * * *" , zone = "Asia/Seoul")

미설정시 local 시간대를 사용한다.

oracle에서 제공하는 문서를 참조하여 입력 한다.

https://docs.oracle.com/cd/B13866_04/webconf.904/b10877/timezone.htm

 

- copy coding -


123

+ Recent posts