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

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如