spring practise

mvc:annotation-driven 的作用

May 17, 2016 | | Say something

相关的代码在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser.parse 方法中实现的,分别注册RequestMappingHandlerMapping,RequestMappingHandlerAdapter,ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver 到spring 容器,对于RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver一个重要的属性是messageConverters 用来进行消息转换。如果jackson和jaxb 库在classpath下,那么就会注册Jaxb2RootElementHttpMessageConverter和MappingJackson2HttpMessageConverter,当一个RequestMapping方法添加了@ResponseBody注解后,就会相应地转为json或者xml字符串

Spring Security简单实践

Feb 1, 2016 | | Say something

demo下载:test_security.zip 网上讲这个主题的帖子很多,而且《spring in action》和《spring security reference》的Security Namespace Configuration节有详细的介绍。本文就提供一个基于maven的demo工程供大家快速起步好了。 本demo有两个请求路径 http://localhost:8080/test_security/admin/test2.do http://localhost:8080/test_security/test1.do 添加了如下的用户信息 username   授权 ——————————————————– root            ROLE_ADMIN,ROLE_COMMON rex              ROLE_ADMIN hml            ROLE_COMMON 有如下的权限映射信息:

所以root能访问这两个url,而rex能访问第一个,hml能访问第二个,具体参考applicationContext.xml文件的配置 注意点如下: 1、如果<security:http>元素的use-expressions=’true’,那么不能在<security:intercept-url>元素的access属性值中使用IS_AUTHENTICATED_ANONYMOUSLY等系统常量,只能使用access=”isAnonymous()”这样的表达式。当<security:http use-expressions=”true”> 激活SpEL表达式的时候,不支持使用角色名。 不然会抛出如下异常 java.lang.IllegalArgumentException: Failed to evaluate expression ‘IS_AUTHENTICATED_ANONYMOUSLY’ 2、当自定义登陆view的时候,要将login.jsp排查在spring security的验证范围,不然就没法登陆了。 3、如果启用了csrf机制,那么login.jsp页面要如下配置 […more]

spring mvc一个处理方法返回不同类型的数据

Aug 12, 2015 | | Say something

有时我们希望处理成功后返回生成的html代码片段,失败的时候返回如下的json对象 {“success”:false, “msg”:”输入有误”} 可以按如下的方式配置view和view resolver

这样在我们的方法中返回jsonView时表示交由MappingJackson2JsonView处理生成json字符串。

本文由javacoder.cn提供

使用atomikos处理ActiveMQ在Spring环境的XA事务

Apr 3, 2015 | | Say something

demo:  testjms-xa.zip   密码:javacoder.cn ActiveMQ完全遵循jms规范,而jms是支持事务的,即要么全部成功,要么全部失败。很多时间,我们的JMS操作需要和数据库操作的事务一致,即要么jms和数据库操作都成功,要么jms和数据库操作都失败,这就是分布式事务(xa事务, 也就是所谓的两段式提交事务,在java中的编程接口为JTA)的用武之地。 完美实现j2ee规范的web server是提供对JTA的实现的,但是tomcat,jetty等轻量级的web server没有提供,在j2se环境也没有,幸运的是还有第三的实现。atomikos就是其中的一个,因其有完整的文档,活跃的社区,商业的支持,而成为第三方jta实现的佼佼者。本文就使用该实现来实践xa事务。 步骤: 为了让本demo有最大的可移植性,本文使用h2数据库,而h2虽然是嵌入式数据库,但是它实现了xa事务,这正是我需要的。 1、新建一个maven 工程 2、在pom.xml中添加对应的依赖 主要有spring-jms,spring-jdbc,activemq-all,com.atomikos:transactions-jta,com.atomikos:transactions-jdbc,com.atomikos:transactions-jms,com.h2database:h2 3、新建schema.sql,用于创建测试用的表

4、新建applicationContext.xml 配置对应的bean,具体可以参考附件中的对应文件,注意xa.dataSource和xa.connectionFactory bean的定义,都指定了init-method=”init” destroy-method=”close”属性,因为在init方法中会将其加入Transaction Manager中去。 2)为了便于管理h2数据库,我声明了org.h2.tools.Server ,这样就可以将浏览器指向http://localhost:8082/来查看h2数据库的内容。 5、开发service类

代码很简单,将User对象同时插入数据库和ActiveMQ队列。只要有某一步操作异常,就会造成数据库和ActiveMQ操作都回滚。使用了Spring经典的声明式事务@Transactional,当发生JdbcSQLException或者RuntimeException时回滚。 6、添加main方法来触发测试

代码很简单,我们构造了两个User对象,注意我们将user 两次加入到了list中,目的为了造成主键重复!! 从context中获取TestXaService对象,调用testXaService.persistence(list)来持久化该list中的对象。 7、测试: 1、启动ActiveMQ 服务器 2、运行程序,发现插入失败,ActiveMQ事务和数据库事务都回滚;将user对象只插入一次到list中,事务提交成功。 参考文档: 1、《ActiveMQ in action》 2、Configuring ActiveMQ transactions in Spring 3、atomikos官网 4、Atomikos TransactionsEssentials Guide.pdf

在spring中使用JMS实现请求/响应模式

Mar 25, 2015 | | Say something

demo下载:testjms-request-reply.zip 1、JMS的实现原理 当发起请求时,调用session.createTemporaryQueue()创建一个临时的Queue,调用requestMessage.setJMSReplyTo(responseQueue)将临时Queue和requestMessage关联,这个动作已经被jmsTemplate.sendAndReceive()方法封装了,调用该方法就会返回responseMessage.当应答端收到requestMessage,调用session.createProducer()创建一个messageProducer,调用session.createTextMessage()创建一个message,使用messageProducer.send(requestMsg.getJMSReplyTo(), replyMsg),通过请求中的ReplyTo通道将响应返回给请求端。 2、CorrelationID头设置 如果在请求端你想知道某个响应是和哪个请求关联的。那么我们可以给Message对象添加CorrelationID头,使用jmsTemplate.sendAndReceive()方法的大致代码如下(参考:cn.javacoder.testjms_send.App):

3、响应端的实现 jmsTemplate 没有提供类似receiveAndReply()的方法,所以需要我们自己编码来实现。大致的代码如下(参考:cn.javacoder.testjms_receive.Reply):

4、参考文档: 1)http://activemq.apache.org/how-should-i-implement-request-response-with-jms.html 2)《ActiveMQ in Action》

Spring整合ActiveMQ实践

Mar 24, 2015 | | Say something

demo下载:testjms.zip ActiveMQ是一个开源的消息中间件,完美的遵循JMS规范,Spring提供了spring-jms模块来简化jms集成。所以给基于spring的应用添加jms功能是轻松愉快加浪漫的。 ActiveMQ提供了两种消息模式:Queue和topic,这两种消息模式的区别为: Queue模式下,Provider发布的一条消息只能被一个Consumer消费。 topic模式下,Provider发布的一条消息能被多个Consumer消费。 开发步骤: 1、搭建ActiveMQ的环境 1)去ActiveMQ的官方下载ActiveMQ服务器,http://activemq.apache.org 2)启动ActiveMQ服务器,Windows下为:cd ${ActiveMQ-dir}/bin目录,执行activemq start 3)访问控制台,http://localhost:8161/admin,用户名和密码为[admin/admin],如果能正常访问,那么服务器搭建成功 2开发消息的Provider端(附件的testjms-send工程) 1)使用maven的maven-archetype-quickstart向导创建一个maven工程 2)在pom.xml中添加如下的依赖

添加log4j是便于spring-jms输出日志信息。 3)在src/main/resources下新增log4j.properties文件 4)在src/main/resources下新增applicationContext.xml文件 该文件的完整内容如下:

声明了三个bean,connectionFactory,queue,jmsTemplate, connectionFactory类似jdbc的Connection对象,表示要链接的服务器的信息。 queue类似jdbc的某张表,表示将消息存在的位置。本例使用的队列模式 jmsTemplate是spring-jms提供的一个模板类,封装了jms操作时的一些例行代码。 5)接下来看看main方法:

main方法很简单,填充了一个User对象[注意发送端和接收端的对象的包名必须一致,且要实现Serialize接口]。利用applicationContext.xml构造了一个applicationContext对象,ApplicationContext中获取一个SendService对象,调用send()方法将user对象发送到ActiveMQ服务器中。 6)最后看看SendService的实现

超级简单,@Component声明SendService类能被自动注册, 注入了JmsTemplate对象,在send()中调用jmsTemplate.send()发送消息,本例发送的是一个ObjectMessage。 7)测试: 执行本demo,访问http://localhost:8161/admin,如图: 表示ActiveMQ确实收到了一条消息。 Consumer端实现(testjms-receive工程) 基本的步骤类似于Provider端的实现,下面讲讲不同点: 1、main()入口 由于DefaultMessageListenerContainer采用的是Deamon实现方式,所以当我们的应用停止的时候我们应该将其shutdown 具体代码参见main()方法:

使用 System.in.read();调用阻塞主线程,当我们通过键盘输入一些字符回车后DefaultMessageListenerContainer被shutdown 2)MessageDriven接收端实现 如果我们调用jms的receive接口方法,如果队列中没有可读的消息,那么当前线程将阻塞直到有消息可用或者超时为止。那能不能等有消息的时候让ActiveMQ主动的回调Consumer呢,这就是MessageDriven bean的思想啦。 spring-jms对MessageDriven bean的支持相当给力,即提供了DefaultMessageListenerContainer 类,也提供了jms命名空间的<jms:listener-container>指令。直接使用DefaultMessageListenerContainer类需要你的回调类实现MessageListener接口,如我在demo中ReceiveService2类的处理逻辑。使用<jms:listener-container>指令,那么你的回调类就是一个POJO类啦,这就是spring-jms所谓的MessageDriven POJO。具体可以参考我的ReceiveService类的实现以及<jms:listener-container>元素的声明。 3)测试: 运行Consumer,后,会发现控制台打印出了如下的信息: from MessageListener —>username:javacoder.cn|email:javacoder.cn@hotmail.com […more]

使用Spring MVC构建RESTful应用

Mar 21, 2015 | | Say something

Demo 下载:spring-mvc-rest.zip 原理简介: 主流的浏览器在实现http1.1协议时基本都只实现了GET和POST方法,rest提倡使用http原本的语义:使用GET获取资源,使用POST新建资源,使用DELETE删除资源,使用PUT更新资源。为了透明的实现DELETE和PUT方法,spring mvc提供了一个spring form标签库,在浏览器中看看最后产生的html代码就一目了然。当我们在jsp页面声明一个<sf:form>元素时,所有的POST,DELETE, PUT方法都是通过POST提交的,只是针对DELETE,PUT产生一个隐藏域来标示实际的http 方法。为了将POST替换成具体的http方法,我们在web.xml中配置HiddenHttpMethodFilter来完成这个动作。 为了根据请求中的Accept头产生相适应的响应,比如Accept=”application/json”那么返回json字符串。spring MVC提供了ResponseBody注解,当一个方法的返回值被ResponseBody注解所修饰,那么就不会使用view resolver来渲染视图,而是使用MessageConverter将方法的返回值转换成客户端希望的格式。 实现步骤: 1、使用maven的maven-archetype-webapp向导创建一个maven web工程 2、修改pom.xml添加对应的依赖,包括spring mvc的依赖,json库, 如果要返回xml需要添加jaxb库。 3、修改修改web.xml声明HiddenHttpMethodFilter和DispatchServlet 4、创建spring的Application Context文件mvc-servlet.xml,在这个文件中,我主要配置了一下的信息: <mvc:resources>静态资源的的请求都映射到/resources/目录 <mvc:annotation-driven/> 和<context:component-scan base-package=”cn.javacoder.restdemo.controller”/>启用注解驱动的bean注册机制,将cn.javacoder.restdemo.controller包下所有的用@Controller, @Component, @Service注解的类注册到spring容器中。 InternalResourceViewResolver配置了一个view resolver。 5、在WEB-INF下创建jsp\rest.jsp文件。演示了spring form标签库的使用,主要是使用spring from发起一个PUT 请求和对象域绑定。 6、本demo涉及到两个java文件,UserController.java(Controller,处理http请求) 和User.java(dto对象,为了能自动转换为xml,添加了jaxb注解) 测试: 使用maven执行jetty:run来启动jetty server 1)执行rest GET请求 http://localhost:8080/spring-mvc-rest/rest 效果如图: 2)点击提交,触发PUT请求 3)测试MessageConverter http://localhost:8080/spring-mvc-rest/testConverter 对于firefox, 执行以下步骤来发送Accept=”application/json”的请求: 在浏览器地址栏输入about:config -> 点击 “I’ll be careful , i promise” […more]

spring ApplicationContext配置文件的加载过程

Dec 2, 2014 | | Say something

我们在基于spring + spring mvc架构的项目的web.xml中看到如下的经典配置:(定义了两个配置xml文件,将servlet相关的对象定义在一个xml中;其他的定义在另一xml中,比如dao层对象,service对象等)

在这段代码中,有pplicationContext.xml 和mvc-applicationContext.xml两个配置文件, 前者通过<context-param>配置,后者作为DispatcherServlet的参数,那么这两个配置文件是加载的,它们是构成一个ApplicationContext,还是构成多个呢,如果是构成两个ApplicationContext,那么这两个ApplicationContext是如何协调工作的?这就是本博文将要回答的问题。 其实所有的问题就藏在ContextLoaderListener 和 DispatcherServlet的源码当中!!! ContextLoaderListener位于spring-web-3.1.1.RELEASE.jar中, ServletContextListener实现了ServletContextListener接口,系统启动时会回调contextInitialized()方法。

将加载的任务委托给了ContextLoader.initWebApplicationContext()方法,该方法的主要代码如下:

在这个方法中,利用context-param中指定的配置文件初始化ApplicationContext,然后以WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为key,注册为servletContext的一个属性。 DispatcherServlet位于spring-webmvc-3.1.1.RELEASE.jar中 DispatcherServlet的继承关系为: DispatcherServlet |–FrameworkServlet |–HttpServletBean initServletBean将初始化的任务委托给initWebApplicationContext()

在initFrameworkServlet()中包含如下代码

这个函数的作用就是从ServletContext中获取以WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为key的ApplicationContext对象,如果返回的值不为空,将其作为新创建的ApplicationContext的parent。具体的逻辑在createWebApplicationContext(ApplicationContext parent)中

在这个方法中,创建了一个ApplicationContext对象wac,将其parent设置为传入的ApplicationContext,也就是使用<context-param>中指定的配置文件初始化的ApplicationContext。然后使用DispatcherServlet自身的ApplicationContext初始化wac。 总结: 我们的示例中,spring初始化了两个ApplicationContext,<context-param>中指定的配置文件(applicationContext.xml)初始化的ApplicationContext是DispatcherServlet中指定的配置文件(mvc-applicationContext.xml)初始化的ApplicationContext的父Context。

Spring MVC中使用JasperReport

Oct 12, 2014 | | Say something

JasperReport Report是一款强大的免费报表引擎,Spring MVC提供了对其的支持,由于JasperReport可以使用多种数据员,本文以javabean为数据源演示。 下载地址: spring-mvc-demo_v4.zip 注意,本教程在写作的过程中maven 下载itext-2.1.7.js2.jar时总是下载不成功,可以翻墙手工下载,然后放在maven对应的目录下,maven的本地仓库目录默认为C:\Users\用户名\.m2\repository目录。 实现步骤 1、使用ireport设计报表模板(略) 本文生成的模板文件为Simple.jasper, 放在src/main/resources/reports/下,编译后会出现在WEB-INF/classes/reports/目录下。 2、修改pom.xml导入需要的依赖。 本系列示例开始使用的是spring 3.2.3 release 版本,为了使用Jasperreport, 升级为了spring 4.1.0 release版本,因为Jasperreport的package改变了,有Jasperreport改成了net.sf.jasperreports。本文使用的依赖为

 3、修改views.properties views.properties是ResourceBundleViewResolver 使用的一个配置文件,具体内容可以参考我的上一篇博客

simpleReport指定逻辑视图的名字 simpleReport.(class)指定视图的实现类 simpleReport.url指定模板文件位置 simpleReport.reportDataKey指定数据在Model中的Key 4、实现一个@Controller方法

SimpleFactory.test() 是我在设计模板时使用的产生数据的工厂方法。可以看到我们返回的逻辑视图是simpleReport且Model中的Key=reportDataKey 5、测试 访问http://localhost:8080/mvcDemo/report 就可以看到我们刚才产生的报表了 报表的内容很简单,就不截图了。

Spring MVC中使用ResourceBundleViewResolver返回json数据

Oct 11, 2014 | | Say something

Demo 下载:spring-mvc-demo_v3.zip  提取码: P1pEyIg5 ResourceBundleViewResolver的原理是读取WEB-INF/classes目录下的某个properties文件,默认为views.properties,可以通过basename属性自定义。 该文件的内容为: jsonView.(class)=org.springframework.web.servlet.view.json.MappingJacksonJsonView #jsonView.url=XXX jsonView.(class)表示当逻辑路径为jsonView时使用MappingJacksonJsonView解析。如果类需要参数可以通过jsonView.url的形式传递参数。 1、在src/main/resources目录下新建view.properties文件,内容为: jsonView.(class)=org.springframework.web.servlet.view.json.MappingJacksonJsonView 2、配置mvc-servlet.xml <bean id=”resourceBundleViewResolver” class=”org.springframework.web.servlet.view.ResourceBundleViewResolver”> <property name=”basename” value=”views” /> <property name=”order” value=”100″ /> </bean> <bean id=”internalResourceViewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”> <property name=”prefix” value=”/WEB-INF/jsp/” /> <property name=”suffix” value=”.jsp” /> </bean> 3、其他的和Spring MVC返回json数据 中介绍的一样 4、运行测试: http://localhost:8080/mvcDemo/json 返回:{“list”:[],”name”:”javacoder.cn”}