카테고리 없음

231212_Maven, REST API, 스프링 프레임워크와 스프링부트

Seungyeon.Jung 2023. 12. 12. 17:54

CHAPTER07-6 Maven 기반 프로젝트 구성

Maven 은 자바 빌드 도구로, 스프링 프레임 워크 개발에서 기본 빌드 도구로 활용되었다. 이후 Gradle가 나오고나서 안드로이드 앱 기발의 기본 빌드 도구가 되었다. Mavem과 Gradle은 현재 가장 대표적인 빌드 도구다. 이클립스에서 Maven 프로젝트를 사용할 땐 주로 웹 프젝트를 Maven기반으로 변환해 사용한다. 

jwbook 폴더에서 configure-convert to maven Project 선택

프로젝트에서 우클릭, Configure →Convert to Maven Project을 선택하면 POM을 생성하는 창이 뜬다. 필요한 사항을 등록한 뒤 Finish를 클릭하면 pom.xml 이 자동으로 생성된 것을 볼 수 있다. 이후 메이븐 리포지터리(https://mvnrepository.com/) 에 접속해서 JSTL을 검색해 코드를 붙여넣는다. 

이하 더보기는 메이븐 리포지터리에서 코드를 복사하는 방법이다.

더보기

 

https://mvnrepository.com/artifact/javax.servlet/jstl/1.2

 

 

 

  <!--라이브러리 추가-->
  <dependencies>
	<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>jstl</artifactId>
	    <version>1.2</version>
	</dependency>
  </dependencies>

생성된 pom.xml 파일에 라이브러리를 추가 끝났다면 pom.xml 우클릭-maven-update project 해야한다.

 

이전 수업에서 학생명단으로 작업할 때 사용했던 라이브러리들을 모두 추가했다. (모두 추가한 뒤 Maven 폴더를 열어봤을 때 아래와 같이 확인 된다. 이전에는 별도로 라이브러리를 폴더에 넣어서 사용했으나, 지금은 Maven에 사용하던 라이브러리를 코드로 넣었고 문제없이 작동되는걸 확인했다.)

뭔가 많다.

 


CHAPTER12 REST API 개발

pom.xml 에 라이브러리를 추가했으나 최신 버전은 호환이 되지 않아 2.33 버전으로 수정해서 업데이트 했다. 이후, 12장 실습을 위해 ch10 폴더를 추가하고서 ch12챕터의 코드를 추가했다.

	<!--12장-->
	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
	<dependency>
	    <groupId>org.glassfish.jersey.containers</groupId>
	    <artifactId>jersey-container-servlet</artifactId>
	    <version>2.33</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
	<dependency>
	    <groupId>org.glassfish.jersey.inject</groupId>
	    <artifactId>jersey-hk2</artifactId>
	    <version>2.33</version>
	</dependency>

	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
	<dependency>
	    <groupId>org.glassfish.jersey.media</groupId>
	    <artifactId>jersey-media-json-jackson</artifactId>
	    <version>2.33</version>
	</dependency>
package ch12;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestConfig extends Application{	
    public Map<String, Object> getProperties() {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("jersey.config.server.provider.packages", "ch12");
        return properties;
    }
}
package ch12;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("/test")
public class RestApiExample {

//	@GET
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	public String sayHello() {
		return "Hello API Service"; //.../api/test
	}
	// .../api/test?msg="abc"
//	@POST
	@GET
	public String sayHello(@QueryParam("msg") String msg) {
		return msg+" API Service";
	}
}

 

HTTP @POST 요청 결과
HTTP @GET 요청 결과

 

 


CHAPTER13 스프링 프레임워크와 스프링부트

pom.xml 에 아래 라이브러리를 추가했다.

<dependency>
         <groupId>org.apache.tomcat.embed</groupId>
         <artifactId>tomcat-embed-jasper</artifactId>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
      </dependency>

application.properties 파일에 아래 내용을 추가했다.

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

이후 테스트를 위한 컨트롤러 (TestWebController.java) 를 작성한다. 위의 설정이 모두 끝난 뒤, 이클립스 콘솔에서 스프링부트 실행했다. 결과를 확인하려면 Run→Run on Server로 실행하는 것이 아닌, 웹 브라우저에서 경로(http://localhost:8080/test/hello)를 직접 작성해서 결과를 확인해야 한다. (경로가 test/hello 인 이유는 TestWebController.java 에서 확인 가능.)

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body> 
	<h2>Hello World</h2>
	<hr>
	현재 날짜와 시간은 <%=java.time.LocalDateTime.now()%> 입니다.
	<hr>
	메시지: ${msg}
</body>
</html>

실행 결과

`


CHAPTER10 뉴스기사 관리 웹 서비스

 

뉴스 등록 시 페이지
뉴스목록을 통해 위와 같이 접속, 다만 이미지는 에러가 뜬다.

 

뉴스기사 관리 웹 서비스에 사용된 파일들은 더보기 참고.

더보기

newsView.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
<title>뉴스 관리 앱</title>
</head>
   <body>
   <div class="container w-75 mt-5 mx-auto">
    <h2>뉴스 목록</h2>
    <hr>
    <ul class="list-group">
		<c:forEach var="news" items="${newslist}" varStatus="status">
		  <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"><a href="news.nhn?action=getNews&aid=${news.aid}" class="text-decoration-none">[${status.count}] ${news.title}, ${news.date}</a>
		  <a href="news.nhn?action=deleteNews&aid=${news.aid}"><span class="badge bg-secondary">&times;</span></a>
		  </li>
		</c:forEach> 
	</ul>
	<hr>
	<c:if test="${error != null}">
		<div class="alert alert-danger alert-dismissible fade show mt-3">
				에러 발생: ${error}
			<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
		</div>
	</c:if>
	<button class="btn btn-outline-info mb-3" type="button" data-bs-toggle="collapse" data-bs-target="#addForm" aria-expanded="false" aria-controls="addForm">뉴스 등록</button>
	<div class="collapse" id="addForm">
	  <div class="card card-body">
		<form method="post" action="/jwbook/news.nhn?action=addNews" enctype="multipart/form-data">
			<label class="form-label">제목</label>
			<input type="text" name="title" class="form-control">
			<label class="form-label">이미지</label>
			<input type="file" name="file" class="form-control">
			<label class="form-label">기사내용</label>
			<textarea cols="50" rows="5" name="content" class="form-control"></textarea>
			<button type="submit" class="btn btn-success mt-3">저장</button>
		</form>
	  </div>
	</div>
	</div>
</body>
</html>

 

newsList.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
<title>뉴스 관리 앱</title>
</head>
   <body>
   <div class="container w-75 mt-5 mx-auto">
    <h2>뉴스 목록</h2>
    <hr>
    <ul class="list-group">
		<c:forEach var="news" items="${newslist}" varStatus="status">
		  <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"><a href="news.nhn?action=getNews&aid=${news.aid}" class="text-decoration-none">[${status.count}] ${news.title}, ${news.date}</a>
		  <a href="news.nhn?action=deleteNews&aid=${news.aid}"><span class="badge bg-secondary">&times;</span></a>
		  </li>
		</c:forEach> 
	</ul>
	<hr>
	<c:if test="${error != null}">
		<div class="alert alert-danger alert-dismissible fade show mt-3">
				에러 발생: ${error}
			<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
		</div>
	</c:if>
	<button class="btn btn-outline-info mb-3" type="button" data-bs-toggle="collapse" data-bs-target="#addForm" aria-expanded="false" aria-controls="addForm">뉴스 등록</button>
	<div class="collapse" id="addForm">
	  <div class="card card-body">
		<form method="post" action="/jwbook/news.nhn?action=addNews" enctype="multipart/form-data">
			<label class="form-label">제목</label>
			<input type="text" name="title" class="form-control">
			<label class="form-label">이미지</label>
			<input type="file" name="file" class="form-control">
			<label class="form-label">기사내용</label>
			<textarea cols="50" rows="5" name="content" class="form-control"></textarea>
			<button type="submit" class="btn btn-success mt-3">저장</button>
		</form>
	  </div>
	</div>
	</div>
</body>
</html>

 

news.sql

drop table news;

CREATE TABLE news (
	aid INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	title VARCHAR NOT NULL,
	img VARCHAR NOT NULL,
	date TIMESTAMP,
	content VARCHAR NOT NULL
);

 

News,java

package ch10;

/**
 * @author dinfree
 *
 */
public class News {
	private int aid;
	private String title;
	private String img;
	private String date;
	private String content;
	
	public int getAid() {
		return aid;
	}
	public void setAid(int aid) {
		this.aid = aid;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getImg() {
		return img;
	}
	public void setImg(String img) {
		this.img = img;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
}

 

NewsController.java

img를 저장하는 폴더를 찾지 못해 그 부분의 절대 경로를 업로드했다. 

package ch10;

import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.apache.commons.beanutils.BeanUtils;

import ch10.News;
import ch10.NewsDAO;

@WebServlet("/news.nhn")
@MultipartConfig(maxFileSize=1024*1024*2, location="D:\\Dev-Fullstack2023\\img")
public class NewsController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	private NewsDAO dao;
	private ServletContext ctx;
	
	// 웹 리소스 기본 경로 지정
	private final String START_PAGE = "ch10/newsList.jsp";
	
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		dao = new NewsDAO();
		ctx = getServletContext();		
	}

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String action = request.getParameter("action");
		
		dao = new NewsDAO();
		
		// 자바 리플렉션을 사용해 if, switch 없이 요청에 따라 구현 메서드가 실행되도록 함.
		Method m;
		String view = null;
		
		// action 파라미터 없이 접근한 경우
		if (action == null) {
			action = "listNews";
		}
		
		try {
			// 현재 클래스에서 action 이름과 HttpServletRequest 를 파라미터로 하는 메서드 찾음
			m = this.getClass().getMethod(action, HttpServletRequest.class);
			
			// 메서드 실행후 리턴값 받아옴
			view = (String)m.invoke(this, request);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			// 에러 로그를 남기고 view 를 로그인 화면으로 지정, 앞에서와 같이 redirection 사용도 가능.
			ctx.log("요청 action 없음!!");
			request.setAttribute("error", "action 파라미터가 잘못 되었습니다!!");
			view = START_PAGE;
		} catch (Exception e) {
			e.printStackTrace();
		}
	
		// POST 요청 처리후에는 리디렉션 방법으로 이동 할 수 있어야 함.
		if(view.startsWith("redirect:/")) {
			// redirect/ 문자열 이후 경로만 가지고 옴
			String rview = view.substring("redirect:/".length());
			response.sendRedirect(rview);
		} else {
			// 지정된 뷰로 포워딩, 포워딩시 컨텍스트경로는 필요없음.
			RequestDispatcher dispatcher = request.getRequestDispatcher(view);
			dispatcher.forward(request, response);	
		}
	}
    
    public String addNews(HttpServletRequest request) {
		News n = new News();
		try {						
			// 이미지 파일 저장
	        Part part = request.getPart("file");
	        String fileName = getFilename(part);
	        if(fileName != null && !fileName.isEmpty()){
	            part.write(fileName);
	        }	        
	        // 입력값을 News 객체로 매핑
			BeanUtils.populate(n, request.getParameterMap());
			
	        // 이미지 파일 이름을 News 객체에도 저장
	        n.setImg("/img/"+fileName);

			dao.addNews(n);
		} catch (Exception e) {
			e.printStackTrace();
			ctx.log("뉴스 추가 과정에서 문제 발생!!");
			request.setAttribute("error", "뉴스가 정상적으로 등록되지 않았습니다!!");
			return listNews(request);
		}
		
		return "redirect:/news.nhn?action=listNews";
		
	}

	public String deleteNews(HttpServletRequest request) {
    	int aid = Integer.parseInt(request.getParameter("aid"));
		try {
			dao.delNews(aid);
		} catch (SQLException e) {
			e.printStackTrace();
			ctx.log("뉴스 삭제 과정에서 문제 발생!!");
			request.setAttribute("error", "뉴스가 정상적으로 삭제되지 않았습니다!!");
			return listNews(request);
		}
		return "redirect:/news.nhn?action=listNews";
	}

	public String listNews(HttpServletRequest request) {
    	List<News> list;
		try {
			list = dao.getAll();
	    	request.setAttribute("newslist", list);
		} catch (Exception e) {
			e.printStackTrace();
			ctx.log("뉴스 목록 생성 과정에서 문제 발생!!");
			request.setAttribute("error", "뉴스 목록이 정상적으로 처리되지 않았습니다!!");
		}
    	return "ch10/newsList.jsp";
    }
    
    public String getNews(HttpServletRequest request) {
        int aid = Integer.parseInt(request.getParameter("aid"));
        try {
			News n = dao.getNews(aid);
			request.setAttribute("news", n);
		} catch (SQLException e) {
			e.printStackTrace();
			ctx.log("뉴스를 가져오는 과정에서 문제 발생!!");
			request.setAttribute("error", "뉴스를 정상적으로 가져오지 못했습니다!!");
		}

    	return "ch10/newsView.jsp";
    }
        
    // multipart 헤더에서 파일이름 추출
	private String getFilename(Part part) {
        String fileName = null;   
        // 파일이름이 들어있는 헤더 영역을 가지고 옴
        String header = part.getHeader("content-disposition");
        //part.getHeader -> form-data; name="img"; filename="사진5.jpg"
        System.out.println("Header => "+header);

        // 파일 이름이 들어있는 속성 부분의 시작위치를 가져와 쌍따옴표 사이의 값 부분만 가지고옴
        int start = header.indexOf("filename=");
        fileName = header.substring(start+10,header.length()-1);        
        ctx.log("파일명:"+fileName);        
        return fileName; 
	}
}

 

NewsDAO.java

getAll 에서 날짜부분 쿼리에서 에러가 떠 String sql = "select aid, title, date from news"; 로 수정했다. 그 외에 날짜가 관련되는 부분들을 전체적으로 수정하고,   cdate는 date로 수정했다.

package ch10;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class NewsDAO {
	final String JDBC_DRIVER = "org.h2.Driver";
	final String JDBC_URL = "jdbc:h2:tcp://localhost/~/jwbookdb";
	
	// DB 연결을 가져오는 메서드, DBCP를 사용하는 것이 좋음
	public Connection open() {
		Connection conn = null;
		try {
			Class.forName(JDBC_DRIVER);
			conn = DriverManager.getConnection(JDBC_URL,"jwbook","1234");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	public List<News> getAll() throws Exception {
		Connection conn = open();
		List<News> newsList = new ArrayList<>();
		
		String sql = "select aid, title, date from news";
		PreparedStatement pstmt = conn.prepareStatement(sql);
		ResultSet rs = pstmt.executeQuery();
		
		try(conn; pstmt; rs) {
			while(rs.next()) {
				News n = new News();
				n.setAid(rs.getInt("aid"));
				n.setTitle(rs.getString("title"));
				n.setDate(rs.getString("date")); 
				
				newsList.add(n);
			}
			return newsList;			
		}
	}
	
	public News getNews(int aid) throws SQLException {
		Connection conn = open();
		
		News n = new News();
		String sql = "select aid, title, img, date, content from news where aid=?";
	
		PreparedStatement pstmt = conn.prepareStatement(sql);
		pstmt.setInt(1, aid);
		ResultSet rs = pstmt.executeQuery();
		
		rs.next();
		
		try(conn; pstmt; rs) {
			n.setAid(rs.getInt("aid"));
			n.setTitle(rs.getString("title"));
			n.setImg(rs.getString("img"));
			n.setDate(rs.getString("date"));
			n.setContent(rs.getString("content"));
			pstmt.executeQuery();
			return n;
		}
	}
	
	public void addNews(News n) throws Exception {
		Connection conn = open();
		
		String sql = "insert into news(title,img,date,content) values(?,?,CURRENT_TIMESTAMP(),?)";
		PreparedStatement pstmt = conn.prepareStatement(sql);
		
		try(conn; pstmt) {
			pstmt.setString(1, n.getTitle());
			pstmt.setString(2, n.getImg());
			pstmt.setString(3, n.getContent());
			pstmt.executeUpdate();
		}
	}
	
	public void delNews(int aid) throws SQLException {
		Connection conn = open();
		
		String sql = "delete from news where aid=?";
		PreparedStatement pstmt = conn.prepareStatement(sql);
		
		try(conn; pstmt) {
			pstmt.setInt(1, aid);
			// 삭제된 뉴스 기사가 없을 경우
			if(pstmt.executeUpdate() == 0) {
				throw new SQLException("DB에러");
			}
		}
	}
}

 

뉴스 목록에서 이미지를 불러오지 못하는 문제가 있다. 수업 시간이 끝나서 문제점을 더 찾아보지는 못하고 다음 수업 때 이미지를 불러올 수 있는 방법이 있는지 다시 찾아볼 계획이다.


사용된 pom.xml 코드 전문

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>jwbook</groupId>
  <artifactId>jwbook</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>17</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
      </plugin>
    </plugins>
  </build>
  
  <!--라이브러리 추가-->
  <dependencies>
	<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>jstl</artifactId>
	    <version>1.2</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
	<dependency>
	    <groupId>com.h2database</groupId>
	    <artifactId>h2</artifactId>
	    <version>2.2.224</version>
	    <scope>runtime</scope>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
	<dependency>
	    <groupId>commons-beanutils</groupId>
	    <artifactId>commons-beanutils</artifactId>
	    <version>1.9.4</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
	<dependency>
	    <groupId>org.apache.commons</groupId>
	    <artifactId>commons-collections4</artifactId>
	    <version>4.4</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
	<dependency>
	    <groupId>commons-logging</groupId>
	    <artifactId>commons-logging</artifactId>
	    <version>1.3.0</version>
	</dependency>
	
	<!--12장-->
	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
	<dependency>
	    <groupId>org.glassfish.jersey.containers</groupId>
	    <artifactId>jersey-container-servlet</artifactId>
	    <version>2.33</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
	<dependency>
	    <groupId>org.glassfish.jersey.inject</groupId>
	    <artifactId>jersey-hk2</artifactId>
	    <version>2.33</version>
	</dependency>

	<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
	<dependency>
	    <groupId>org.glassfish.jersey.media</groupId>
	    <artifactId>jersey-media-json-jackson</artifactId>
	    <version>2.33</version>
	</dependency>


  </dependencies>
</project>