[๊ฐœ๋ฐœ ํ™˜๊ฒฝ]

์„œ๋ฒ„: Spring Boot 3.2.4

ํ”„๋ก ํŠธ: Vite + React + TypeScript

 

<MyController.java>

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {

    @RequestMapping(value = "/gnbmenu")
    public String gnbMenu(@RequestBody Object request) {
        String str = "{\"message\" : \"๋ฉ”๋‰ด ์š”์ฒญ url.\"}";
        return str;
    }

}

 

<MyFront.tsx>

import { useEffect } from "react";

function MyFront() {
  const dataToSend = {
    key1: "value1",
    key2: "value2",
  };
  useEffect(() => {
    fetch("/api/gnbmenu", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(dataToSend),
    }).then((response) => console.log(response.json()));
  }, []);

  return <></>;
export default MyFront;

 

<Server Console>

2024-04-18T20:10:29.643+09:00 ERROR 26416 --- [****] [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [{"message" : "๋ฉ”๋‰ด ์š”์ฒญ url."}], template might not exist or might not be accessible by any of the configured Template Resolvers] with root cause

org.thymeleaf.exceptions.TemplateInputException: Error resolving template [{"message" : "๋ฉ”๋‰ด ์š”์ฒญ url."}], template might not exist or might not be accessible by any of the configured Template Resolvers
	at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869) ~[thymeleaf-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:607) ~[thymeleaf-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1103) ~[thymeleaf-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1077) ~[thymeleaf-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.thymeleaf.spring6.view.ThymeleafView.renderFragment(ThymeleafView.java:372) ~[thymeleaf-spring6-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.thymeleaf.spring6.view.ThymeleafView.render(ThymeleafView.java:192) ~[thymeleaf-spring6-3.1.2.RELEASE.jar:3.1.2.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1431) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1167) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1106) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) ~[tomcat-embed-core-10.1.19.jar:6.0]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.5.jar:6.1.5]
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.19.jar:6.0]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.5.jar:6.1.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.5.jar:6.1.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.5.jar:6.1.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]

 

<Client console>

MyFront.tsx:36 
 POST http://localhost:5173/api/gnbmenu 500 (Internal Server Error)
(anonymous)	@	MyFront.tsx:36
Show 10 more frames

 

[์˜ˆ์ƒ ๋ฌธ์ œ 1]

๊ฒฝ๋กœ ์„ค์ • ๋ฌธ์ œ?

"/abc"๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ์—์„œ "/"์„ ์ œ๊ฑฐํ•˜๊ณ  "abc"ํ˜•ํƒœ๋กœ ์ˆ˜์ • โ˜ž AWS๋‚˜ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋กœ ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ์•„๋‹˜

 

[๋ฌธ์ œ 2]

Controller Annotaion ์ข…๋ฅ˜์˜ ๋ฌธ์ œ

@Controller๋Š” ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ view๋ฅผ ์ฐพ์Œ. view๊ฐ€ ์•„๋‹Œ jsonํ˜•ํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— @RestController๋กœ ์„ค์ • โ˜ž ํ•ด๊ฒฐ

 

๋ฐ˜์‘ํ˜•
package com.study.controller;

import org.apach.commons.io.FileUtils;
import org.springFamework.http.HttpHeaders;
import org.springFamework.http.HttpStatus;
import org.springFamework.http.MediaType;
import org.springFamework.http.ResponseEntity;


@Controller
public class AttachFileController {

	@RequestMapping("/pdfView")
    public ResponseEntity<byte[]> pdfView(HttpServletRequest request, HttpServletResponse) throws Exception{
    	request.setCharacterEncoding("utf-8");
        String fileId = new String(request.getParameter("fileId".getBytes("8859_1", "KSC5601");
        // fileId ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
        // fileId์— ํ•ด๋‹นํ•˜๋Š” ํŒŒ์ผ ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
              
        String filePath = ${FILES_ROOT_PATH} + fileId;
        String tempFile = new File(filePath);
        byte[] pdfBytes;
        
        try {
        	pdfBytes = org.apache.commons.io.FileUtils.readFileToByteArray(tempFile);
        } catch (Exception e){
        	e.printStackTrace();
            String error = "<script tye='text/javascript'> alert('File Not Found');</script>";
            byte[] arrorBytes = error.getBytes(StandardCharsets.UTF_8);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorBytes);
            }
            
        HttpHeaders = headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.setContentDispositionFormData("filename", "example.pdf");
        headers.setContentLength(pdfBytes.length);
        //ํŒŒ์ผ์ด ๋‹ค์šด๋กœ๋“œ ๋˜์ง€ ์•Š๊ณ  ๋ธŒ๋ผ์šฐ์ € ๋‚ด์— ๋ณด์ด๋„๋ก ํ•จ
        headers.set("Content-Disposition", "inline; filename=example.pdf"
        
        return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK);
    }

}
๋ฐ˜์‘ํ˜•

ํ”„๋กœ์ ํŠธ๋ฅผ ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•˜๋Š” ๊ณผ์ • ์ค‘์— ๋ชจ๋ฅด๋Š”๊ฒƒ, ๋ฌธ์ œ๋“ค์— ๋Œ€ํ•ด์„œ ๋‹ค์‹œ ์ฐพ์•„๋ณด๋Š” ์‹œ๊ฐ„์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ž‘์„ฑ

Spring Framework๋กœ ์ž‘์„ฑํ–ˆ๋˜ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์˜ pom.xml ์ตœ์ƒ๋‹จ ๋ถ€๋ถ„. ์•„๋ž˜๋กœ๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ? ๋“ค์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ์žˆ์Œ.

groupId,  artiactedId, version ๊ฐ ํ”„๋กœ์ ํŠธ๋ณ„๋กœ ์žˆ๊ณ  ์˜์กด์„ฑ์ฃผ์ž…์„ ํ•œ ํ”„๋กœ์ ํŠธ๋“ค์—๋„ ๋ชจ๋‘ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์ตœ์ƒ๋‹จ์˜ ๋‚ด์šฉ์€ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ groupId,  artiactedId, version์„ ์˜๋ฏธํ•œ๋‹ค.

 

[๊ณต์‹ ๋ฌธ์„œ์˜ ์„ค๋ช… + ์ฐพ์•„๋ณธ ์ •๋ณด]

groupId: ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๋Š” ๊ฒƒ

- Java์˜ ํŒจํ‚ค์ง€ ์ด๋ฆ„ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•œ๋‹ค.

(๊ฐ•์ œ ๊ทœ์น™์€ ์•„๋‹ˆ์ง€๋งŒ ์—ญ๋„๋ฉ”์ธ์ด๋ฆ„(์ฆ‰, Java ํŒจํ‚ค์ง€ ์ด๋ฆ„)์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋‹จ์–ดํ•˜๋‚˜๋กœ ์“ฐ๋ฉด

  Maven Central ์ €์žฅ์†Œ์—์„œ ํ”„๋กœ์ ํŠธ์˜ ID๋กœ ์Šน์ธ ๋ฐ›๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ)

- Java ํŒจํ‚ค์ง€ ์ด๋ฆ„ ๊ทœ์น™์„ ๋”ฐ๋ผ์„œ ํ•˜์œ„๊ทธ๋ฃน์„ ์ƒ์„ฑํ•  ์ˆ˜ ๋„ ์žˆ์Œ

artifactId: ๋ฒ„์ „ ์—†์ด jar ํŒŒ์ผ์˜ ์ด๋ฆ„

- ์†Œ๋ฌธ์ž๋กœ ๋œ ๋ฌธ์ž๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•จ

- ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋งŒ๋“  jar ํŒŒ์ผ์ธ ๊ฒฝ์šฐ ๋ฐฐํฌ๋˜๋Š” ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
์˜ˆ: maven, commons-math

- ์›น ํ”„๋กœ์ ํŠธ์˜ Context root๋กœ ์ž๋™ ์„ค์ •๋œ๋‹ค. → ์ด Context root๋Š” ๋ฐฐํฌํ• ๋•Œ url ์„ค์ •๊ณผ ๊ด€๋ จ ์žˆ..๋Š”๊ฑฐ ๊ฐ™์Œ

pom.xml์—  artifactId๊ฐ€ controller๋กœ ๋˜์–ด์žˆ์–ด์„œ Context root๋„ /controller ๋กœ ๋˜์–ด ์žˆ์Œ.

์™œ ์ €๋ ‡๊ฒŒ ํ•ด๋†จ๋Š”์ง€๋Š” ๋‹น์—ฐํžˆ ๋ชจ๋ฆ„... ๊ทธ๋ƒฅ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ setting์„ ๋ณต์‚ฌํ•ด์„œ ์จ์„œ ๊ทธ๋Ÿฐ๊ฒƒ ๊ฐ™์Œ. ๊ทธ๋ž˜์„œ artifactId์™€ ํ•จ๊ป˜ ๋ฐ”๊ฟˆ

 

 

 

 

 

 

 

 

 

version: ๋ง๊ทธ๋Œ€๋กœ ๋ฐฐํฌํ•˜๋Š” ํ”„๋กœ์ ํŠธ์˜ ๋ฒ„์ „

- ์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ (1.0, 1.1, 1.0.1 ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ์ง€๋งŒ,

๋‚ ์งœ๋Š” ๋ณดํ†ต SNAPSHOT ๋นŒ๋“œ์™€ ์—ฐ๊ด€๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•จ.

- ๋‹ค๋ฅธ์‚ฌ๋žŒ์˜ artifact์ธ ๊ฒฝ์šฐ ๋ฒ„์ „ ๋ฒˆํ˜ธ ์›๋ž˜ ์ ํžŒ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•จ.

 

์ถœ์ฒ˜ : https://maven.apache.org/guides/mini/guide-naming-conventions.html

 

Maven – Guide to Naming Conventions

 

maven.apache.org

Guide to naming conventions on groupId, artifactId, and version

  • groupId uniquely identifies your project across all projects. A group ID should follow Java's package name rules. This means it starts with a reversed domain name you control. For example,org.apache.maven, org.apache.commonsYou can create as many subgroups as you want. A good way to determine the granularity of the groupId is to use the project structure. That is, if the current project is a multiple module project, it should append a new identifier to the parent's groupId. For example,
  • org.apache.maven, org.apache.maven.plugins, org.apache.maven.reporting
  • Maven does not enforce this rule. There are many legacy projects that do not follow this convention and instead use single word group IDs. However, it will be difficult to get a new single word group ID approved for inclusion in the Maven Central repository.
  • artifactId is the name of the jar without version. If you created it, then you can choose whatever name you want with lowercase letters and no strange symbols. If it's a third party jar, you have to take the name of the jar as it's distributed.eg. maven, commons-math
  • version if you distribute it, then you can choose any typical version with numbers and dots (1.0, 1.1, 1.0.1, ...). Don't use dates as they are usually associated with SNAPSHOT (nightly) builds. If it's a third party artifact, you have to use their version number whatever it is, and as strange as it can look. For example,2.0, 2.0.1, 1.3.1

+ ์œ„์˜ ์ •๋ณด๋“ค์„ ํ†ตํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋“ค์ด ํŠธ๋ฆฌ ํ˜•ํƒœ๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ํ•จ.

    ⇒๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์—์„œ ๋‚˜์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์‹๋ณ„์ž๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด๋  ๊ฒƒ ๊ฐ™์Œ

packaging : ํŒจํ‚ค์ง• ํ•  ํ˜•์‹

๋นŒ๋“œ ํ›„ ํ”„๋กœ์ ํŠธ ํŒŒ์ผ์˜ ์ด๋ฆ„๊ณผ ํ˜•์‹์ด ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ๋‹ค.

 

์ถœ์ฒ˜ : https://youtu.be/KNGQ9JBQWhQ

 

๋ฐ˜์‘ํ˜•

+ Recent posts