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

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机