jersey+jetty+jdk8实现restful接口

2024-04-20 07:08

本文主要是介绍jersey+jetty+jdk8实现restful接口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

jersey+jetty+jdk8实现restful接口, 嵌入式, 无需tomcat部署,  比springboot轻量.

支持统一异常处理;

支持Date日期序列化,  响应时自动将对象中的日期字段转为自定义格式的时间格式字符串 返回给客户端

 

 

目录结构:

 

build.gradle:

import org.apache.tools.ant.filters.FixCrLfFilter;
import org.apache.tools.ant.filters.ReplaceTokens;apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'eclipse'project.group = 'com.soft'
project.archivesBaseName = 'jersey-jetty'
project.version = ''tasks.withType(JavaCompile) { sourceCompatibility = "1.8"targetCompatibility = "1.8"options.encoding="UTF-8"
}javadoc { options.encoding = "UTF-8" }repositories {mavenLocal()maven{ url "http://maven.aliyun.com/nexus/content/groups/public" }
}dependencies {compile 'cn.hutool:hutool-all:5.3.5'compile 'org.glassfish.jersey.containers:jersey-container-jetty-http:2.34'compile 'org.glassfish.jersey.containers:jersey-container-servlet-core:2.34'compile 'org.glassfish.jersey.inject:jersey-hk2:2.34'compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.34'//compile 'org.eclipse.jetty:jetty-server:9.4.31.v20200723'//compile 'org.eclipse.jetty:jetty-servlet:9.4.31.v20200723'//compile 'org.eclipse.jetty:jetty-util:9.4.31.v20200723'compile 'org.eclipse.jetty:jetty-server:9.4.41.v20210516'compile 'org.eclipse.jetty:jetty-servlet:9.4.41.v20210516'compile 'org.eclipse.jetty:jetty-util:9.4.41.v20210516'compile 'org.slf4j:slf4j-api:2.0.0-alpha1'runtime 'org.slf4j:jcl-over-slf4j:2.0.0-alpha1'runtime 'ch.qos.logback:logback-classic:1.3.0-alpha5'compile group: 'org.mybatis', name: 'mybatis', version: '3.5.4'compile group: 'com.zaxxer', name: 'HikariCP', version: '3.4.5'runtime 'com.oracle:ojdbc6:11.2.0.3'compileOnly 'org.projectlombok:lombok:1.18.12'annotationProcessor 'org.projectlombok:lombok:1.18.12'    
}task libs(type: Copy) {from configurations.runtimeinto "$buildDir/libs"
}task makeJar(type:org.gradle.api.tasks.bundling.Jar) {from('build/classes/java/main')exclude('*.properties', '*.xml','*.setting')
} processResources(){filter(ReplaceTokens,tokens: loadEnv());filter ReplaceTokens, tokens: ["version": version]filter(FixCrLfFilter,eol: FixCrLfFilter.CrLf.newInstance('lf'),tab: FixCrLfFilter.AddAsisRemove.newInstance('asis'),tablength: 4,eof: FixCrLfFilter.AddAsisRemove.newInstance('remove'),fixlast: true)
}task processShell(type: Copy) {description = " copy shell scripts to buildDir/shell"from 'src/main/sh'into "$buildDir/sh"filter(ReplaceTokens,tokens: loadEnv());filter(FixCrLfFilter,eol: FixCrLfFilter.CrLf.newInstance('lf'),tab: FixCrLfFilter.AddAsisRemove.newInstance('asis'),tablength: 4,eof: FixCrLfFilter.AddAsisRemove.newInstance('remove'),fixlast: true)
}test {systemProperties 'property': 'value'
}task deploy(type: Copy) {description = ' deploy all the binary and config files to destination(prefix) 'def destFold=file("$prefix")into(destFold)from("$buildDir/libs"){into("lib")}from("$buildDir/sh"){into("sh")}from("$buildDir/resources/main"){into("conf")}doFirst{logger.lifecycle("deploy files to : $destFold")}doLast{logger.lifecycle("deploy success!")}
}task preDeploy(){description = ' pre actions for task deploy'def logsdir=file("$prefix/log")if(!logsdir.exists()){logsdir.mkdir();}def libs=fileTree("$prefix/lib")libs.each {jar ->jar.delete()}def configs=fileTree("$prefix/conf")configs.each {conffile ->conffile.delete()}
}libs.dependsOn(makeJar)
build.dependsOn(['libs','processShell','processResources'])deploy.dependsOn preDeploy
deploy.dependsOn build

env/config.groovy:

prefix='/output'environments {dev {sh{WORK_HOME='/home/xxx/newitf/jersey-jetty';PNAME='jersey-jetty';LANG='zh_CN.utf8';JAVA_HOME='/home/xxx/app/jdk/jdk8';}}}

JettyStart  

package com.soft;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.soft.server.JettyServer;public class JettyStart {private static final Logger log = LoggerFactory.getLogger(JettyStart.class);public static void main(String... args) {new JettyStart().start();}private JettyServer server;public JettyStart() {server = new JettyServer();}public void start() {try {server.start();server.join();} catch (Exception e) {log.error("", e);} finally {server.destroy();}}}

JerseyStart  (此类与JettyStart  2个都可以启动服务)

package com.soft;import java.net.URI;import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class JerseyStart {private static final Logger log = LoggerFactory.getLogger(JerseyStart.class);public static void main(String[] args) {try {// uri只有第一个路径段将用作上下文路径,其余部分将被忽略JettyHttpContainerFactory.createServer(URI.create("http://localhost:8080/"), new RestApplication());} catch (Exception e) {log.error("", e);}}
}

 

JettyServer

package com.soft.server;import com.soft.RestApplication;
import com.soft.config.ServerConf;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class JettyServer {private static final Logger log = LoggerFactory.getLogger(JettyServer.class);private static final int port = ServerConf.VO.getPort();private static final String contextPath = ServerConf.VO.getContextPath();private static final String resourceBase = ServerConf.VO.getResourceBase();private static final int maxThreads = ServerConf.VO.getMaxThreads();private static final String ipWhiteList = ServerConf.VO.getIpWhiteList();private Server server;public JettyServer() {}public void start() throws Exception {server = new Server(createThreadPool());server.addConnector(createConnector());server.setHandler(createHandlers());server.setStopAtShutdown(true);server.start();}public void join() throws InterruptedException {server.join();}public void destroy() {server.destroy();}private ThreadPool createThreadPool() {QueuedThreadPool threadPool = new QueuedThreadPool();threadPool.setName("embed-jetty-http");threadPool.setMinThreads(1);threadPool.setMaxThreads(maxThreads);return threadPool;}private ServerConnector createConnector() {ServerConnector connector = new ServerConnector(server);connector.setPort(port);log.info("App start at port: {}", port);return connector;}private HandlerCollection createHandlers() {ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS);handler.setContextPath(contextPath);handler.setResourceBase(resourceBase);ServletHolder holder = handler.addServlet(ServletContainer.class, "/*");holder.setInitOrder(1);holder.setInitParameter("javax.ws.rs.Application", RestApplication.class.getName());HandlerCollection handlerCollection = new HandlerCollection();handlerCollection.setHandlers(new Handler[]{handler});return handlerCollection;}//	private static InetAccessHandler getFireWallHandler() {
//		InetAccessHandler ipHandler = new InetAccessHandler();
//		if (StrUtil.isBlank(ipWhiteList)) {// 空,不配置,则不校验
//			return ipHandler;
//		}
//
//		String[] ipList = ipWhiteList.split(",");
//		for (String ip : ipList) {
//			ipHandler.include(ip);
//		}
//		return ipHandler;
//	}}

UserController:

package com.soft.controller;import java.util.Date;import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.soft.po.User;
import com.soft.util.Result;@Path("/abc")
public class UserController {private static final Logger log = LoggerFactory.getLogger(UserController.class);@GET@Path("/hello")@Produces(MediaType.TEXT_PLAIN)public String hi() {return "hello jersey";}@GET@Path("/{username}/{age}")@Produces(MediaType.APPLICATION_JSON)public Result findByKey(@PathParam("username") String username, @PathParam("age") int age) {log.info("接收到请求" + username);User user = new User();user.setUsername(username);user.setAge(age);user.setStatus(20);user.setModdate(new Date());return Result.ok(user);}
}

Result:

package com.soft.util;import com.soft.exception.ErrorType;import lombok.Data;@Data
public class Result {private String code;private String msg;private Object body;public Result() {}public Result(ErrorType type) {this.code = type.getCode();this.msg = type.getMsg();}public Result(String code, String msg) {this.code = code;this.msg = msg;}public Result(String code, String msg, Object body) {this.code = code;this.msg = msg;this.body = body;}public static Result gen(String code, String msg, Object data) {return new Result(code, msg, data);}public static Result gen(ErrorType type, Object data) {return new Result(type.getCode(), type.getMsg(), data);}public static Result ok() {return gen(ErrorType.Succ, null);}public static Result ok(Object data) {return gen(ErrorType.Succ, data);}public static Result fail(String msg) {return new Result(ErrorType.Fail.getCode(), msg, null);}
}

ErrorType

package com.soft.exception;public enum ErrorType {Succ("0","操作成功"),Fail("1","操作失败"),ReqParamMissing("0001","请求参数缺少"),DataNotExist("1000","数据不存在"),DataExist("1001","数据已存在"),InvalidQuery("1002","无效的查询"),InvalidMod("1003","无效的修改"),SysErr("9999","系统错误");private String code;private String msg;ErrorType(String code,String msg) {this.code=code;this.msg = msg;}public String getCode() {return code;}public String getMsg() {return msg;}
}

ServerConf

package com.soft.config;import cn.hutool.setting.Setting;public class ServerConf {private static final Setting SETTING = new Setting("server.setting");public static final ServerVo VO = SETTING.toBean(ServerVo.class);private ServerConf() {}}

ServerVo:

package com.soft.config;import lombok.Data;@Data
public class ServerVo {private int port;private String contextPath;private String resourceBase;private int maxThreads;private String ipWhiteList;// 逗号分隔ip
}

BUserController 

package com.soft.controller;import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;import com.soft.dao.BBroadbandUserDAO;
import com.soft.exception.AppException;
import com.soft.exception.ErrorType;
import com.soft.exception.ReqException;
import com.soft.po.BBroadbandUser;
import com.soft.util.Result;import cn.hutool.core.util.StrUtil;@Path("/buser")
public class BUserController {@POST@Path("/find")@Consumes(MediaType.APPLICATION_JSON)@Produces(MediaType.APPLICATION_JSON)public Result findByKey(BBroadbandUser req) {String username = req.getUsername();if (StrUtil.isBlank(username)) {throw new ReqException(ErrorType.ReqParamMissing);}BBroadbandUser po = new BBroadbandUser();po.setUsername(username);BBroadbandUserDAO udao = new BBroadbandUserDAO();BBroadbandUser user = udao.queryByPK(po);if (user==null) {throw new AppException(ErrorType.DataNotExist);}return Result.ok(user);}
}

User:

package com.soft.po;import java.util.Date;import lombok.Data;@Data
public class User {private String username;private int age;private int status;private Date moddate;}

 

package com.soft.controller;import com.soft.exception.BaseException;
import com.soft.exception.ErrorType;
import com.soft.util.Result;
import org.eclipse.jetty.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;/*** 异常捕获, 此类必须放在此controller包下,放在其他目录,客户端会抛异常*/
@Provider
public class ExceptionMappingResource implements ExceptionMapper<Throwable> {private static final Logger log = LoggerFactory.getLogger(ExceptionMappingResource.class);@Overridepublic Response toResponse(Throwable t) {Result re = null;if (t instanceof BaseException) {BaseException e = (BaseException) t;re = new Result(e.getCode(), e.getMessage());log.info("{}", re);} else {re = new Result(ErrorType.Fail.getCode(), t.getMessage());log.error("", t);}return Response.status(HttpStatus.INTERNAL_SERVER_ERROR_500).entity(re).build();}}
package com.soft.controller;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJsonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;@Provider
@Produces(MediaType.APPLICATION_JSON)  //必须增加@Produces注解
public class JacksonConf extends JacksonJsonProvider {private static final Logger log = LoggerFactory.getLogger(JacksonConf.class);@Overridepublic void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {//log.info("------------date format convert-------------");// 将写给客户端的数据中的Date类型字段转换为特定格式ObjectMapper mapper = new ObjectMapper();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");mapper.setDateFormat(sdf);// 必须设置, 写给客户端的json数据中,Date类型字段才能转为自定义的格式mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);mapper.writeValue(entityStream, value);// 结果写给客户端}
}

 

package com.soft;import com.soft.controller.JacksonConf;
import org.glassfish.jersey.server.ResourceConfig;import javax.ws.rs.ApplicationPath;//@ApplicationPath("/abc") //注解无效
public class RestApplication extends ResourceConfig {public RestApplication() {System.out.println("---------ResourceConfig---------");// 服务类所在的包路径packages("com.soft.controller");register(JacksonConf.class);// register(JacksonJsonProvider.class);
//		register(ValidationFeature.class);}
}

 

server.setting:

port=8080
contextPath=/
resourceBase=@sh.WORK_HOME@/conf
maxThreads=30
ipWhiteList=

 

说明:

- ExceptionMappingResource必须放在controller目录下,在其他目录,controller代码中抛出自定义异常时,会导致客户端抛异常
- 使用JerseyStart,jetty-server:9.4.40.v20210413版本 启动时, JacksonConf类必须增加注解@Produces(MediaType.APPLICATION_JSON),才能Date日期序列化生效
- 使用JettyStart,jetty-server:9.4.31.v20200723版本 启动时, JacksonConf类无需增加注解@Produces(MediaType.APPLICATION_JSON),也能Date日期序列化生效
- 必须使用jetty 9.4.31.v20200723版本 ,RestApplication配置的Date类型序列化才会成功;稍高版本  jetty 9.4.41.v20210516 也无效,无法转换Date格式.解决: 这是因为未增加注解@Produces(MediaType.APPLICATION_JSON), 增加后可使用jetty9高版本.

这篇关于jersey+jetty+jdk8实现restful接口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/919596

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

MySQL 横向衍生表(Lateral Derived Tables)的实现

《MySQL横向衍生表(LateralDerivedTables)的实现》横向衍生表适用于在需要通过子查询获取中间结果集的场景,相对于普通衍生表,横向衍生表可以引用在其之前出现过的表名,本文就来... 目录一、横向衍生表用法示例1.1 用法示例1.2 使用建议前面我们介绍过mysql中的衍生表(From子句