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

相关文章

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Qt实现发送HTTP请求的示例详解

《Qt实现发送HTTP请求的示例详解》这篇文章主要为大家详细介绍了如何通过Qt实现发送HTTP请求,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、添加network模块2、包含改头文件3、创建网络访问管理器4、创建接口5、创建网络请求对象6、创建一个回复对

C++实现回文串判断的两种高效方法

《C++实现回文串判断的两种高效方法》文章介绍了两种判断回文串的方法:解法一通过创建新字符串来处理,解法二在原字符串上直接筛选判断,两种方法都使用了双指针法,文中通过代码示例讲解的非常详细,需要的朋友... 目录一、问题描述示例二、解法一:将字母数字连接到新的 string思路代码实现代码解释复杂度分析三、

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

Gin框架中的GET和POST表单处理的实现

《Gin框架中的GET和POST表单处理的实现》Gin框架提供了简单而强大的机制来处理GET和POST表单提交的数据,通过c.Query、c.PostForm、c.Bind和c.Request.For... 目录一、GET表单处理二、POST表单处理1. 使用c.PostForm获取表单字段:2. 绑定到结

springMVC返回Http响应的实现

《springMVC返回Http响应的实现》本文主要介绍了在SpringBoot中使用@Controller、@ResponseBody和@RestController注解进行HTTP响应返回的方法,... 目录一、返回页面二、@Controller和@ResponseBody与RestController

nginx中重定向的实现

《nginx中重定向的实现》本文主要介绍了Nginx中location匹配和rewrite重定向的规则与应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下... 目录一、location1、 location匹配2、 location匹配的分类2.1 精确匹配2

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst