最近发现公司里有点人心惶惶,裁员,裁员,也不知道会不会轮到我,做技术的最大好处就是面对这样的局面,心理总是比较坦然的,不过要是突然来了变故,总会恶心下自己,还是为了自己的生存而努力吧。想想自己干了这么多年软件,一直都是java软件工程师,虽然现在比较迷恋前端,但是前端总会被那些不懂的人说成廉价货,所以写几套java框架现在对我而言还是非常的重要的,我想成为技术牛人,想当公司里的首席技术架构师,总不能靠说吧,还得靠自己实实在在的实力,我一定要把这么多年接触过、使用过以及学习过的技术都写出来,没有为自己留下技术成长的痕迹,晚上一定会被遗憾鬼缠上,加油哈!
今天我要把struts2框架引入到我正在写的应用框架里面,我的java web容器使用tomcat,我先建一个index.jsp文件,里面内容很简单,在body里面一句话Hello My javaEE!,然后把工程导入到tomcat下面,这个过程我不写了,不清楚的可以查查baidu。
在浏览器地址栏里填写http://localhost:8080/ssiprj/index.jsp,结果如下图:
我们在打包到tomcat下的目录看看,路径如下图:
在javaEE工程里面,配置文件的默认路径都是在WEB-INF\classes下面,这样当tomcat启动时候会自动检测到这些配置文件,而实际上大家看到了我们的配置文件放的极其分散。
为了便于源代码的管理,我都会把配置文件放到统一的文件夹里面,当然也可以分散放置,然后用ant这样的工具进行部署,但我觉得再去编写ant文件太麻烦,而且我现在写这套框架要有重点,锦上添花的事情到了后面扩展时候在做讨论,我现在工程里面没有用到ant,而我的配置文件是这么写的,大家先看我的工程的目录结构,如下图:
conf和src在同一个层级的目录下,我修改了工程目录下的.classpath文件,里面添加了<classpathentry kind="src" path="conf"/>以及修改了编译后的文件输入的文件夹<classpathentry kind="output" path="WebContent/WEB-INF/classes"/>,完全的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="conf"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk16">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/sringmvcstudy">
<attributes>
<attribute name="owner.project.facets" value="jst.web"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="WebContent/WEB-INF/classes"/>
</classpath>
以前写dao,service时候引用配置文件的路径要做下修改,现在是默认路径,不用指定到那个文件夹,修改的文件有(代码框里上面是源代码,下面部分是修改后的代码):
applicationContext.xml:
<!-- 读取资源文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:conf/constants.properties</value>
</list>
</property>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>classpath:conf/SqlMapConfig.xml</value>
</property>
<property name="dataSource" ref="myDataSource"/>
</bean>
----------------------------------------------------------------------------
<!-- 读取资源文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:constants.properties</value>
</list>
</property>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>classpath:SqlMapConfig.xml</value>
</property>
<property name="dataSource" ref="myDataSource"/>
</bean>
web.xml文件:
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext*.xml</param-value>
</context-param>
-----------------------------------------------------------
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
我们再看看部署到tomcat工程目录下的配置文件,如下图:
配置文件被解析到了WEB-INF\classes目录下了。
下面我们正式导入struts2框架了,首先我在工程新添加如下jar包,如下图:
接下来我修改了web.xml配置文件,如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>ssiprj</display-name>
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<!-- 将spring框架装载进我们的工程里 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts-cleanup</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
里面加了三个过滤器,其中struts2这个过滤器就可以让工程里加载struts2框架,encodingFilter过滤器让所用的请求响应都用UTF-8字符来处理;而actionContextcleanup过滤器来清除从前
台页面获得的属性,这个写在配置里好处蛮多的,因为有时action缓存数据会造成一些很难发现的bug。
然后我在conf目录下建立struts.xml配置文件,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.action.extension" value="do,action,htm"/>
<constant name="struts.configuration.files" value="struts-default.xml,struts-plugin.xml,struts.xml"/>
</struts>
接下来我在cn.com.sharpxiajun.common.action下新建了一个BaseAction,作为action的基类,代码如下:
package cn.com.sharpxiajun.common.action;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;
import com.opensymphony.xwork2.ActionSupport;
public class BaseAction extends ActionSupport implements ServletRequestAware,
ServletResponseAware, SessionAware, ServletContextAware {
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private ServletContext context = null;
private Map<String, Object> map = null;
@Override
public void setServletContext(ServletContext context) {
this.context = context;
}
@Override
public void setSession(Map<String, Object> map) {
this.map = map;
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletResponse getResponse() {
return response;
}
public void setResponse(HttpServletResponse response) {
this.response = response;
}
public ServletContext getContext() {
return context;
}
public void setContext(ServletContext context) {
this.context = context;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}
这里我除了继承ActionSupport外,还实现了ServletRequestAware,ServletResponseAware, SessionAware, ServletContextAware四个接口,这四个接口可以让我们获得Servlet的四个原生对象request、response、session和ServletContext,使用struts框架常常会让我们忘记了上面四个对象,但是有些时候用原生态的这些对象还是非常有好处的。BaseAction基类可以做action一些公用的方法,我们现在先做一个雏形,以后再慢慢扩展了。
在cn.com.sharpxiajun.action包下新建UsersAction类,它继承BaseAction,代码如下:
package cn.com.sharpxiajun.action;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import cn.com.sharpxiajun.common.action.BaseAction;
import cn.com.sharpxiajun.service.UsersService;
@SuppressWarnings("serial")
@Scope("prototype")
@Controller("usersAction")
public class UsersAction extends BaseAction {
@Autowired
@Qualifier("usersService")
private UsersService usersService = null;
//输入值
private String usernamequery;//查询条件
private String username;//新增的用户名
private String password;//新增密码
private Integer enabled = 1;
//输出值
private List<Map<String, Object>> results = null;//返回查询的列表
private String msg = null;//系统运行信息
private String flag = null;//操作状态标记
private String welcome = null;//欢迎语
public String usersinit() throws Exception
{
welcome = "欢迎使用本系统!";
return SUCCESS;
}
public String queryUsersList() throws Exception{
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", usernamequery);
results = this.usersService.queryUsersList(map);
flag = "success";
msg = "查询操作成功!";
welcome = "你的查询操作已经完成!";
return SUCCESS;
}
public String addUsers()
{
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", username);
map.put("password", password);
map.put("enabled", enabled);
try {
this.usersService.addUsers(map);
} catch (Exception e) {
flag = "error";
msg = "新增操作失败!";
e.printStackTrace();
return ERROR;
}
flag = "success";
msg = "新增操作成功!";
welcome = "你的新增操作已经完成!";
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Map<String, Object>> getResults() {
return results;
}
public void setResults(List<Map<String, Object>> results) {
this.results = results;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public String getWelcome() {
return welcome;
}
public void setWelcome(String welcome) {
this.welcome = welcome;
}
public Integer getEnabled() {
return enabled;
}
public void setEnabled(Integer enabled) {
this.enabled = enabled;
}
public String getUsernamequery() {
return usernamequery;
}
public void setUsernamequery(String usernamequery) {
this.usernamequery = usernamequery;
}
}
里面有两个方法,一个是查询数据,一个方法做新增操作。@Controller注解表明这是MVC的控制层。
在conf下面,我再添加一个配置文件struts-action.xml,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="action" extends ="struts-default">
<action name="queryUsersList" class="usersAction" method="queryUsersList">
<result name="success">/WEB-INF/jsp/users.jsp</result>
</action>
<action name="usersinit" class="usersAction" method="usersinit">
<result name="success">/WEB-INF/jsp/users.jsp</result>
</action>
<action name="addUsers" class="usersAction" method="addUsers">
<result name="success">/WEB-INF/jsp/users.jsp</result>
<result name="error">/WEB-INF/common/error.jsp</result>
</action>
</package>
</struts>
其实struts2也可以零配置的,但是我这个框架里面我不想在控制层加入它本身的零配置特性,我在写dao和service都是尽量用零配置,但是零配置真的那么好嘛?我一直不这么认为,当然我现在也没有想到它的重要缺点,但是控制层里的struts2的action配置我还是写道配置文件里,那么在UsersAction里的注解就只是逻辑层次的配置,这样各个逻辑层的注解都是统一的,然后我们在struts.xml里面加入这一句话:
<include file="struts-action.xml"/>
如下图结构,我们在WEB-INF下面建立jsp包,里面新建users.jsp文件
代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!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=UTF-8">
<title>用户信息</title>
</head>
<body>
<form name="queryForm" method="post" action="queryUsersList.action">
<h1>系统返回值:<s:property value="welcome"/></h1>
<br/>
用户名:<input type="text" id="usernamequery" name="usernamequery"/> <input type="submit" value="query"/>
</form>
<br/>
<br/>
<table border="1">
<thead>
<tr>
<th>用户名</th>
<th>密码</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<s:iterator value="results">
<tr>
<td>
<s:property value="username"/>
</td>
<td>
<s:property value="password"/>
</td>
<td>
<s:property value="enabled"/>
</td>
</tr>
</s:iterator>
</tbody>
</table>
<form name="addForm" method="post" action="addUsers.action">
<br/>
用户名:<input type="text" id="username" name="username"/>
<br/>
密码:<input type="text" id="password" name="password"/>
<br/>
<input type="submit" value="ADD"/>
</form>
</body>
</html>
<%@ taglib prefix="s" uri="/struts-tags" %>:我们在页面里面导入了struts标签;
页面里有两个form,name="queryForm" 的form做查询操作,name="addForm"的form做新增操作。
启动tomcat服务器。
我们在地址栏填入:http://localhost:8080/ssiprj/usersinit.action结果如下:
我们直接点击query按钮,结果如下:
我录入用户名:sharpxiajun;密码:sharpxiajun,点击ADD按钮,在点击query按钮,结果如下:
数据新增成功了。
最后总结下了:我的框架现在看起来比较完整了,从客户端可以一直到数据库了,一马平川,这个感觉很爽,不过现在的struts用到的特性并不是我期望用到的,我会把action返回给前端的数据封装成json对象,而前段也是封装成json传递给action,这个就符合一切层与层之间的通讯都是用键值对的形式,前端我会使用到ajax,这是前端的方向所在,另外,我不会在客户端使用自定义标签,客户端是设计者的天地,只有javascript才能塑造最完美的页面。后面我还会使用到模板语言velocity,freemarker,图形技术jfreechart以及和这个做对比的fusioncharts(可惜是要钱的),服务端也有很多内容可以加进去,比如调度,缓存,webservice,mq等等,要是都写完简直是一个奇妙之旅。