Spring MVC 与ExtJS完美集成
一、简介
本 demon 主要是集成了 SpringMVC 和 ExtJS ,同时还支持 controller 页面配置、页面消息可配置(类似于国际化)、 intercepter 示例。
二、系统集成
1 、包文件
包文件的重要性就不多说了,建议用 maven 管理。
但是,为了加深理解,我是直接从官网上下载的包,然后一个个试的,中间遇到了很多问题,包括少包,包冲突等。
2 、配置文件
先看 web.xml 。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SpringMVCTest</display-name> <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <!-- 防止资源文件被spring MVC拦截 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
然后是 root-context.xml, 默认的没有加内容。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Root Context: defines shared resources visible to all other web components --> </beans>
最后是 servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <annotation-driven /> <!--防止css js img 文件被拦截 <resources mapping="/images/**" location="/images/" cache-period="31556926" /> <resources mapping="/js/**" location="/js/" cache-period="31556926" /> <resources mapping="/css/**" location="/css/" cache-period="31556926" /> --> <!-- 加入集中消息文件的配置 //也可以用来支持进行国际化--> <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <beans:property name="basenames" value="/WEB-INF/message/static_message , /WEB-INF/message/dynamic_message" /> <beans:property name="cacheSeconds" value="2"></beans:property> </beans:bean> <!-- 能够让controller返回json格式的配置 //当然也可以自己手动拼json或者用工具类生成json 将拼好的json串写到页面上 然后再返回页面--> <beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <beans:property name="messageConverters"> <beans:list> <beans:ref bean="mappingJacksonHttpMessageConverter" /> </beans:list> </beans:property> </beans:bean> <beans:bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <beans:property name="supportedMediaTypes"> <beans:list> <beans:value>application/json;charset=UTF-8</beans:value> </beans:list> </beans:property> </beans:bean> <!-- 加入能够进行前端文件访问的配置 不适用默认的视图解释类--> <beans:bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" /> </beans:bean> <beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> <beans:property name="definitions"> <beans:list> <beans:value>/WEB-INF/tiles-defs/templates.xml</beans:value> </beans:list> </beans:property> </beans:bean> <!-- 加入interceptor --> <interceptors> <interceptor> <mapping path="/extjspie" /> <beans:bean id="MeasurementInterceptor" class="com.util.MeasurementInterceptor"> <!-- <beans:property name="paramName" value="theme" /> --> </beans:bean> </interceptor> </interceptors> <context:component-scan base-package="com.controller" /> </beans:beans>
3 、页面配置文件
templates.xml,用来配置前段页面和后台返回的字符串之间的关系。
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN" "http://tiles.apache.org/dtds/tiles-config_2_0.dtd"> <tiles-definitions> <definition name="extjspie" template="/WEB-INF/chart/pie1.jsp"></definition> <definition name="jquerypie" template="/WEB-INF/chart/pie.jsp"></definition> </tiles-definitions>
4 、消息文件
dynamic_message.properties
title = Title : {0}
static_message.properties
check_download = Would you like to download the chart as an image?
5 、页面文件
pie1.jsp (路径 /extjspie 会跳转到这个文件)
<spring:messagecode='title' arguments='pie'/>
这个会使用 message 里的消息,可以对消息进行动态修改而不用重启服务器,一般用于用户消息或系统配置。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<script src="js/extjs/ext-all.js"></script>
<link rel="stylesheet" href="js/extjs/resources/css/ext-all.css">
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<script>
Ext.Loader.setConfig({
enabled : true
});
Ext.require('Ext.chart.*');
Ext.require([ 'Ext.layout.container.Fit', 'Ext.window.MessageBox', 'Ext.grid.*', 'Ext.util.*' ]);
Ext.onReady(function() {
//effort
var store = Ext.create('Ext.data.JsonStore', {
fields : [ 'id', 'name', 'data1' ],
proxy : {
type : 'ajax',
url : 'pieData',
reader : {
type : 'json'
}
}
});
store.load({
callback : function(records, operation, success) {
console.log(records);
}
});
var donut = false, chart = Ext.create('Ext.chart.Chart', {
xtype : 'chart',
animate : true,
store : store,
shadow : true,
legend : {
position : 'right'
},
insetPadding : 60,
theme : 'Base:gradients',
series : [ {
type : 'pie',
field : 'data1',
showInLegend : true,
donut : donut,
tips : {
trackMouse : true,
width : 140,
height : 28,
renderer : function(storeItem, item) {
//calculate percentage.
var total = 0;
store.each(function(rec) {
total += rec.get('data1');
});
this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100)
+ '%');
}
},
highlight : {
segment : {
margin : 20
}
},
label : {
field : 'name',
display : 'rotate',
contrast : true,
font : '18px Arial'
}
} ]
});
Ext.create('widget.panel', {
width : 800,
height : 600,
title : "<spring:message code='title' arguments='pie'/>",
renderTo : "chart",
layout : 'fit',
tbar : [
{
text : 'Save Chart',
handler : function() {
Ext.MessageBox.confirm('Confirm Download', "<spring:message code='check_download' />",
function(choice) {
if (choice == 'yes') {
chart.save({
type : 'image/png'
});
}
});
}
}, {
text : 'Reload Data',
handler : function() {
// Add a short delay to prevent fast sequential clicks
window.loadTask.delay(100, function() {
store1.loadData(generateData(6, 20));
});
}
}, {
enableToggle : true,
pressed : false,
text : 'Donut',
toggleHandler : function(btn, pressed) {
chart.series.first().donut = pressed ? 35 : false;
chart.refresh();
}
} ],
items : chart
});
});
</script>
<body>
<div id="chart"></div>
</body>
</html>
pie.jsp(/jquerypie 会跳转到这个界面 , 主要用来集成 jquery)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<link rel="stylesheet" href="js/jquery/themes/base/jquery.ui.all.css">
<script src="js/jquery/jquery-1.9.1.js"></script>
<script src="js/jquery/ui/jquery.ui.core.js"></script>
<script src="js/jquery/ui/jquery-ui.js"></script>
<script>
$(document).ready(function(){
$.get("pieData", function(data) {
$.each(data,function(InfoIndex,Info){
alert(InfoIndex);
alert(Info["name"]);
});
});
});
</script>
<body>
this is pie.jsp!!
</body>
</html>
6 、后台文件
ChartController.java ( Controller 方法)
package com.controller;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.model.Employee;
@Controller
public class ChartController {
private static final Logger logger = LoggerFactory.getLogger(ChartController.class);
/**
* method description goes here
*
* @param args
*/
@RequestMapping(value = "/jquerypie", method = RequestMethod.GET)
public String pie(Model model) {
// TODO Auto-generated method stub
return "jquerypie";
}
@RequestMapping(value = "/extjspie", method = RequestMethod.GET)
public String pie1(Model model) {
// TODO Auto-generated method stub
return "extjspie";
}
@RequestMapping(value = "/pieData", method = RequestMethod.GET)
@ResponseBody
public Object pieData(Model model) {
// TODO Auto-generated method stub
List<Employee> empList = new ArrayList<Employee>();
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setName("steven");
emp1.setData1(10);
empList.add(emp1);
Employee emp2 = new Employee();
emp2.setId(2);
emp2.setName("daniel");
emp2.setData1(25);
empList.add(emp2);
Employee emp3 = new Employee();
emp3.setId(3);
emp3.setName("emily");
emp3.setData1(7);
empList.add(emp3);
Employee emp4 = new Employee();
emp4.setId(4);
emp4.setName("heather");
emp4.setData1(4);
empList.add(emp4);
//return json data
return empList;
}
}
Employee.java
package com.model;
public class Employee {
private int id;
private String name;
private int data1;
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the data1
*/
public int getData1() {
return data1;
}
/**
* @param data1 the data1 to set
*/
public void setData1(int data1) {
this.data1 = data1;
}
}
MeasurementInterceptor.java(inteceptor 方法 )
package com.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class MeasurementInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,Object handler)throws Exception{
long startTime = System.currentTimeMillis();
request.setAttribute("startTime",startTime);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
request.removeAttribute("startTime");
long endTime = System.currentTimeMillis();
//modelAndView.addObject("handlingTime", endTime - startTime);
System.out.println("______________enter interceptor . use time:" + (endTime - startTime));
}
}
具体效果见下图: