由于即将开始的新项目,是一个对外网开放访问权限的web应用。所以,公司技术管理层不允许使用struts以及spring mvc这一套。所以,我们开始转战曾经用作REST API的框架jersey及其周边工具,实现MVC。

业务逻辑的bean依然采用spring进行管理。

spring mvc是我们团队成员都很熟悉的MVC框架,jersey系列,有的知道有的不知道,其实jersey也比较的简单。只是要有个熟悉的过程。

下面,我就捡起早期的工具,重温一下jersey,新的jersey2进行简单的web应用, 此处的demo采用tomcat8+jersey2+freemarker+spring的架构。

在此,有必要说明一下,对于初学者,可能会很疑惑或者诧异,jersey的jar包,有的是com.sun的,有的是org.glassfish的,对的,这两个是同时存在的,只是com.sun的jersey是jersey 1.x版本,而org.glassfish的版本,俗称jersey2.x版本。

在eclipse里面,创建一个Dynamic web project。当然你也可以采用maven构建项目,我所在的公司环境,maven环境是折磨人的,所以,我选择的是dynamic web project。项目创建好后,就需要准备jersey2以及与spring结合相关的jar文件。我的项目中涉及到的所有的jar文件都在这里,点击可下载。我的jersey2的版本是当前最新的版本2.25.1,spring3的版本是3.2.17.RELEASE。

这个demo很简单,首先看看web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>TGECS</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list> <listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:conf/log4j.properties</param-value>
</context-param> <!-- Spring configuration -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param> <filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <filter>
<filter-name>JerseyServlet</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<!-- 这个类是资源注册类 -->
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.tg.ecs.core.RestConfigService</param-value>
</init-param>
<init-param>
<!-- 这个类是用来注册静态资源 (css,js,images,fonts) -->
<param-name>jersey.config.servlet.filter.staticContentRegex</param-name>
<param-value>(/(css|js|images|fonts)/.*)|(/favicon.ico)</param-value>
</init-param>
<init-param>
<!-- 禁止出现404的时候继续将http请求向下一级filter发送,即一旦出错就退出 -->
<param-name>jersey.config.servlet.filter.forwardOn404</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!--
解决warning信息:The root of the app was not properly defined. Either use a Servlet 3.x
container or add an init-param jersey.config.servlet.filter.contextPath to the filter configuration.
Due to Servlet 2.x API, Jersey cannot determine the request base URI solely from the ServletContext.
The application will most likely not work.
-->
<param-name>jersey.config.servlet.filter.contextPath</param-name>
<param-value></param-value>
</init-param>
<!--
<load-on-startup>2</load-on-startup>
-->
</filter> <filter-mapping>
<filter-name>JerseyServlet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

上述的配置文件中,有两个地方需要说明:

1. JerseyServlet这个filter-name,若改成了servlet,对应的filter-mapping的地方都改成servlet的配置,那么,你将会遇到静态资源文件找不到的问题。如下面图所示,所有的html页面中的css,js,images等静态资源都报404.

这个,官方的解释,可以参考下https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/servlet/ServletProperties.html#FILTER_STATIC_CONTENT_REGEX

public static final String FILTER_STATIC_CONTENT_REGEX
If set the regular expression is used to match an incoming servlet path URI to some web page content such as static resources or JSPs to be handled by the underlying servlet engine.

The property is only applicable when Jersey servlet container is configured to run as a Filter, otherwise this property will be ignored. If a servlet path matches this regular expression then the filter forwards the request to the next filter in the filter chain so that the underlying servlet engine can process the request otherwise Jersey will process the request. For example if you set the value to /(image|css)/.* then you can serve up images and CSS files for your Implicit or Explicit Views while still processing your JAX-RS resources.

The type of this property must be a String and the value must be a valid regular expression.

A default value is not set.

The name of the configuration property is "jersey.config.servlet.filter.staticContentRegex".

See Also:
Constant Field Values

2.jersey2的配置,不同于jersey的配置,资源的配置信息,这里主要是RestConfigService类。具体内容看java代码:

/**
* @author "shihuc"
* @date 2017年4月25日
*/
package com.tg.ecs.core; import java.util.HashMap;
import java.util.Map; import javax.ws.rs.container.ContainerRequestFilter; import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
import org.glassfish.jersey.server.spring.SpringComponentProvider;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter; /**
* @author chengsh05
*
*/
public class RestConfigService extends ResourceConfig{ public RestConfigService(){ //告知jersey扫描controller的路径
packages("com.tg.ecs"); /*
*配置view端的模板信息,本应用前端采用freemarker对页面进行渲染
*/
Map<String, Object> pro = new HashMap<String, Object>();
//模板编码
pro.put(FreemarkerMvcFeature.ENCODING, "UTF-8");
//禁止freemarker的cache,每次都重新编译
pro.put(FreemarkerMvcFeature.CACHE_TEMPLATES, false);
//指定模板基础路径
pro.put(FreemarkerMvcFeature.TEMPLATE_BASE_PATH, "WEB-INF/ftl");
addProperties(pro).register(FreemarkerMvcFeature.class); // register filters
register(RequestContextFilter.class);
register(ContainerRequestFilter.class);
register(SpringComponentProvider.class); // register features
register(JacksonFeature.class);
register(MultiPartFeature.class);
}
}

这个的相关jersey2的配置,看上去是不是很像spring-boot推崇的去xml化,即主要采用JavaConfig的思路。 很方便实现各种功能的配置。

另外, 关于jersey2的一些注解,实现servlet的拦截相关的注解,可以自己复习一下,不多解释。下面这两个是比较重要的,对比spring mvc中,@Produces有点类似@ResponseBody,但是又比它强大。与spring mvc的关系,可以慢慢体会。

@Produces
@Produces注释用来指定将要返回给client端的数据标识类型(MIME)。@Produces可以作为class注释,也可以作为方法注释,方法的@Produces注释将会覆盖class的注释 @Consumes
@Consumes与@Produces相反,用来指定可以接受client发送过来的MIME类型,同样可以用于class或者method,也可以指定多个MIME类型,一般用于@PUT,@POST

还有,@GET,@POST,@Path,@FormParam,@FormDataParam,@QueryParam,@Context等等。

下面,针对@Context,说一下,这个与Spring mvc不同的地方,主要是参数匹配上,在spring mvc的controller的方法上,参数前可以不用明确指定参数类型,但是在jersey里面,需要指定,否则会遇到错误。

四月 ,  :: 上午 org.glassfish.jersey.internal.Errors logErrors
警告: The following warnings have been detected: WARNING: A HTTP GET method, public org.glassfish.jersey.server.mvc.Viewable com.tg.ecs.test.DemoController.home(javax.servlet.http.HttpServletRequest), should not consume any entity.
WARNING: A HTTP GET method, public org.glassfish.jersey.server.mvc.Viewable com.tg.ecs.test.DemoController.login(javax.servlet.http.HttpServletRequest), should not consume any entity.

这个错误,可以通过下面的代码方式进行修改:

@GET
@Path("/home")
@Produces(MediaType.TEXT_HTML)
public Viewable home(@Context HttpServletRequest req) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("basePath", infoService.basePath(req));
return new Viewable("/home", map);
} @GET
@Path("/login")
@Produces(MediaType.TEXT_HTML)
public Viewable login(@Context HttpServletRequest req) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("basePath", infoService.basePath(req));
System.out.println(demoService.say());
return new Viewable("/login", map);
}

即,添加上红色的@Context注解后,上面的错误提示信息就解决了。

@Context对应的使用场合,可以参照官方user-guide进行学习。

3.6. Use of @Context

Previous sections have introduced the use of @Context. Chapter 5 of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with @Context.

When deploying a JAX-RS application using servlet then ServletConfigServletContextHttpServletRequest and HttpServletResponse are available using @Context.

再说说,jersey2到底是如何和spring进行集成的呢?我们的demo里面,主要采用的是基于注解。也就是说,在jersey2里面,只要通过@Resource或者@Autowired等方式,将spring的bean注入到jersey2的servlet中,即可。先来看看我的spring的配置文件吧:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="configRealm" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:conf/internal.properties</value>
<value>classpath:conf/jdbc.properties</value>
<value>classpath:conf/redis.properties</value>
<value>classpath:conf/session.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="properties" ref="configRealm"/>
</bean> <bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:conf/ehcache.xml"/>
</bean> <cache:annotation-driven cache-manager="springCacheManager"/> <context:annotation-config/> <context:component-scan base-package="com.tg.ecs">
</context:component-scan> <import resource="spring-cache.xml"/>
<import resource="spring-dao.xml"/>
<import resource="spring-redis.xml"/>
</beans>

另外,看看,我们的测试用controller的全部代码:

/**
* @author "shihuc"
* @date 2017年4月24日
*/
package com.tg.ecs.test; import java.util.HashMap;
import java.util.Map; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import org.glassfish.jersey.server.mvc.Viewable;
import org.springframework.stereotype.Controller; import com.tg.ecs.core.InfoService; /**
* @author chengsh05
*
*/
@Controller

@Path("/demo")
public class DemoController { @Resource(name="dsi")
private DemoService demoService; @Resource
private InfoService infoService; @GET
@Path("/home")
@Produces(MediaType.TEXT_HTML)
public Viewable home(@Context HttpServletRequest req) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("basePath", infoService.basePath(req));
return new Viewable("/home", map); #不能写成home
} @GET
@Path("/login")
@Produces(MediaType.TEXT_HTML)
public Viewable login(@Context HttpServletRequest req) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("basePath", infoService.basePath(req));
System.out.println(demoService.say());
return new Viewable("/login", map); #不能写成login
} }

这个DemoController里面,一个很重要的地方,就是Viewable里面的第一个参数,指定的是ftl文件的“绝对路径”,这个绝对路径是相对于在RestConfigService里面配置的Freemarker的模板路径而言的。前面配置的freemarker的模板路径在WEB-INF/ftl目录下面,这里,在servlet里面,指定的view的文件路径,必须是相对于模板路径的绝对路径。这个逻辑,和nginx的SSI中virtual的路径指定是一个思路。

另外,上面的@Controller,是spring-context的注解,加这个注解,是为了让spring将bean注入到这个servlet(控制器)里面,这样,当/demo/home或者/demo/login的请求到来时,infoService这个bean就已经初始化了,整个逻辑就跑通了。

到此,基本的demo就算介绍完毕了,有些许spring mvc和jersey的基础的,就很容易理解这里的集成过程。欢迎讨论和转帖。

jersey2+freemarker+spring3的集成的更多相关文章

  1. Struts2 Spring3 Hibernate3 集成xml版本

    Struts2 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互 ...

  2. MyBatis3与Spring3无缝集成-从iBatis平滑过渡

    从2010开始接触iBatis到现在,一直到现在把iBatis作为数据访问层ORM.为了演示一个Web应用,今天又搭了个SpringMVC应用,由于应用比较简单,Spring版本直接用最新版本3.2. ...

  3. SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结

    下载地址: http://pan.baidu.com/s/1qWDinyk 一 开发环境 1.动态web工程 2.部分依赖 hibernate-release-4.1.0.Final.zip hibe ...

  4. spring3.0的jar包详解

    1. spring.jar 是包含有完整发布模块的单个jar 包. 2. org.springframework.aop 包含在应用中使用Spring的AOP特性时所需的类. 3. org.sprin ...

  5. Spring3.0.5jar包用法详解 [转载]

    Spring3.X以后jar包进行了重构,取消了原来2.X版本中的总的spring.jar包,而是把总包中的功能全部分开打包.正在向osgi靠拢. 各个jar包详解如下: 1. org.springf ...

  6. Spring3.0 核心jar包详解

    org.springframework.aop  包含在应用中使用Spring的AOP特性时所需的类. org.springframework.asm   Spring独立的ASM程序, Spring ...

  7. Cxf + Spring3.0 入门开发WebService

    转自原文地址:http://sunny.blog.51cto.com/182601/625540/ 由于公司业务需求, 需要使用WebService技术对外提供服务,以前没有做过类似的项目,在网上搜寻 ...

  8. Spring4 SpringMVC Hibernate4 Freemaker 集成示例

    变更更正(2014-05-30 13:47:22):一些IDE在web.xml我们会报告这个错误: cvc-complex-type.2.4.a: Invalid content was found ...

  9. Spring3.2.2中相关Jar包的作用

    今天在看Spring的源码的时候不知道从什么地方开启应该合适,因为不太清楚实现类所在的具体Jar包,就从网上找了些,可是网上有的说的是不清不楚,甚至是有些错误的,所以就把相关Jar包的大致作用给整理了 ...

随机推荐

  1. JQ 设置控件显示 隐藏

    ("#id").css('display','none'); $("#id").css('display','block'); 或 $("#id&qu ...

  2. date简述

    Date 定义时间和日期的类   java.util.Date 1s=1000ms; 时间的原点:公元1970年1月1日 00点00分00秒: public class DateDemo { publ ...

  3. 前端笔记 (3.JavaScript 1)

    JavaScript 是属于网络的脚本语言! JavaScript 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编程代码. JavaScript 插入 HTML 页面后, ...

  4. [转]使用keepalived搭建主备切换环境

    使用keepalived搭建主备切换环境 时间 2016-09-15 08:00:00 cpper 原文  http://cpper.info/2016/09/15/keepalived-for-ma ...

  5. Kesci: Keras 实现 LSTM——时间序列预测

    博主之前参与的一个科研项目是用 LSTM 结合 Attention 机制依据作物生长期内气象环境因素预测作物产量.本篇博客将介绍如何用 keras 深度学习的框架搭建 LSTM 模型对时间序列做预测. ...

  6. Python之路PythonThread,第一篇,进程1

    python3 进程1 多任务编程: 可以有效的利用计算机资源,同时执行多个任务, 进程:进程就是程序在计算机中一次执行的结果: 进程和程序的区别: 程序是一个静态文件的描述,不占用计算机的系统资源: ...

  7. 获取列表中的最大的N项和最小的N项

    获取列表中的最大的N项和最小的N项 #!/sur/bin/env python # -*- coding:utf-8 -*- # author:zengsf #time:2018/10/31 impo ...

  8. 如何用input标签上传多个图片并回显

    本文主要记录如何用input标签和jquery实现多图片的上传和回显,不会涉及后端的交互,大概的效果看图 我们从零来做一个这样的demo 第一步: 我们先完善一下我们的页面,默认的input-file ...

  9. mysql中不直接通过密码连接 还要指定ip地址进行连接----------DCL数据库控制语言

    线上如果用root超级用户连接数据库,非常容易造成隐私泄漏.一般线上不用root数据控制. 今天和大家分享的是  输入密码还不可以连接数据库,必须要输入ip地址以后,才可以连接. 正常的访问数据库都是 ...

  10. 【HAOI2014】走出金字塔

    神奇…… 原题: 在探险的过程中,考古学家Dr. Kong 无意地被困在一个金字塔中.金字塔中的每个房间都是三角形.Dr. Kong可以破壁走到相邻的房间去. 例如,如果他目前处于三角形(2,2)房间 ...