java web 分层之—5层架构

JSP 表现层---》Dispatch 分发请求--》Command 交互层---》service 业务逻辑层---》Dao 数据访问层---》数据库

上图为demo程序的总体结构,其中framework包下是“框架”程序,二次开发人员无须改动。 
  

表现层:index.jsp

<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>Insert title here</title>

<script type="text/javascript">

function doSubmit() {

var username = document.getElementById("username").value;
var password = document.getElementById("password").value;

if (username == "" || password == "") {
//alert("用户名和密码不能为空!");
document.getElementById("tips").innerHTML="<font color='red'>用户名和密码不能为空!</span>";
} else {
document.loginForm.submit();
}
}
</script>
</head>
<body>
<span id="tips"></span>
<form name="loginForm" action="user.cmd.UserCommand.do?method=login" method="post">
用户名:
<input type="text" id="username" name="username" >

密码:
<input type="password" id="password" name="password" >

<input type="button" value="提交" onclick="doSubmit()">
</form>
</body>
</html>

web.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_2_5.xsd"
version="2.5"> 
   <servlet>
   <servlet-name>dispatch</servlet-name>
   <servlet-class>tool.Dispatch</servlet-class>
   </servlet>
   
   <servlet-mapping>
   <servlet-name>dispatch</servlet-name>
   <url-pattern>*.do</url-pattern>
   </servlet-mapping>
</web-app>

分发器:Dispatch.java,拦截所有.do结尾的请求,并将请求转发给相应的cmd进行处理。

package framework.dispatch;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import framework.context.CommandContext;
import framework.factory.InstanceFactory;

public class Dispatch extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {

		//设置编码
		req.setCharacterEncoding("GBK");

		//解析请求的url
		StringBuffer url = req.getRequestURL();

		//http://localhost:8080/test4/UserCommand.do
		int a = url.lastIndexOf("/");
		int b = url.lastIndexOf(".do");

		//获取请求的cmd的类名(含包路径)
		String cmdName = url.substring(a + 1, b);//substring(begin(含),end(不含)),即[)

		try {

			//获取请求的cmd的实例
			Object cmdObj = InstanceFactory.getInstance(cmdName);
			
			//设置Command上下文信息,放于线程变量中。
			CommandContext.init(req, resp, getServletContext(), getServletConfig());
			
			//获取请求的方法名
			String methodName = req.getParameter("method");
			
			//执行请求的方法,cmd层的方法
			Method realMehood = cmdObj.getClass().getMethod(methodName);
			String forwardPath = realMehood.invoke(cmdObj).toString();

			//执行完毕,进行页面跳转
			if(forwardPath != null){			
				req.getRequestDispatcher(forwardPath).forward(req, resp);
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} 
	}
}

  
CommandContext,以线程变量的方式存储当前线程的request、response、servletcontext、servletconfig对象。

package framework.context;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CommandContext {

	private static ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal<Map<String,Object>>();
	
	private static final String HTTP_SERVLET_REQUEST = "1";
	private static final String HTTP_SERVLET_RESPONSE = "2";
	private static final String SERVLET_CONTEXT = "3";
	private static final String SERVLET_CONFIG = "4";
	
	/*
	 * 初始化线程局部变量
	 */
	public static void init(HttpServletRequest req,HttpServletResponse resp,ServletContext context,ServletConfig config){
		threadLocal.remove();
		Map<String,Object> localMap = new HashMap<String, Object>();
		localMap.put(HTTP_SERVLET_REQUEST, req);
		localMap.put(HTTP_SERVLET_RESPONSE, resp);
		localMap.put(SERVLET_CONTEXT, context);
		localMap.put(SERVLET_CONFIG, config);
		threadLocal.set(localMap);
	}
	/*
	 * 获取request对象
	 */
	public static HttpServletRequest getRequest(){
		return (HttpServletRequest)threadLocal.get().get(HTTP_SERVLET_REQUEST);
	}
	/*
	 * 获取response对象
	 */
	public static HttpServletResponse getResponse(){
		return (HttpServletResponse)threadLocal.get().get(HTTP_SERVLET_RESPONSE);
	}
	/*
	 * 获取servletContext对象
	 */
	public static ServletContext getServletContext(){
		return (ServletContext)threadLocal.get().get(SERVLET_CONTEXT);
	}
	/*
	 * 获取servletConfig对象
	 */
	public static ServletConfig getServletConfig(){
		return (ServletConfig)threadLocal.get().get(SERVLET_CONFIG);
	}
}

  

   command交互层:

package user.cmd;

import framework.context.CommandContext;
import framework.factory.InstanceFactory;
import user.service.UserService;

public class UserCommand {
	
	UserService userService = InstanceFactory.getInstance(UserService.class.getName());
	
	/*
	 * 执行登录验证
	 */
	public String login(){
		
		String username = CommandContext.getRequest().getParameter("username");
		String password = CommandContext.getRequest().getParameter("password");
		
		//调用service层
		boolean isOk = userService.checkLogin(username, password);
		if(isOk){
			return "ok.jsp";
		}
		return "fail.jsp";
	}
}

  

service层:UserService.java

package user.service;

import framework.db.TransactionManager;
import framework.factory.InstanceFactory;
import user.dao.UserDao;


public class UserService {
	
	UserDao dao = InstanceFactory.getInstance(UserDao.class.getName());

	/*
	 * 执行登录验证
	 */
	public boolean checkLogin(String username, String password) {

		if (password == null) {
			return false;
		}
		String pass = null;
		
		//拿到事务管理器
		TransactionManager tm = TransactionManager.getTransManager();
		try {
			//开启事务
			tm.beginTransaction();
			
			pass = dao.getPassword(username);
			
			//提交事务
			tm.commitTransaction();
		} catch (RuntimeException e) {
			e.printStackTrace();
			tm.rollbackTransaction();//出现异常则回滚事务
		}
		if (password.equals(pass)) {
			return true;
		} else {
			return false;
		}
	}
}

Dao层:

package user.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import framework.db.DBUtil;

//--创建表 T_USERS
//CREATE TABLE T_USERS(
//    USERNAME VARCHAR2(10) NOT NULL,
//    PASSWORD VARCHAR2(60) NOT NULL
//);
//--设置主键
//ALTER TABLE T_USERS ADD CONSTRAINT T_USERS_PK PRIMARY KEY(USERNAME);

public class UserDao {
	
	/*
	 * 根据用户名,查询密码
	 */
	public String getPassword(String username){
		
		String pass = null;
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet set = null;
	
		try{
			conn = DBUtil.getCon();
			ps = conn.prepareStatement("select password from t_users where username=?");
			ps.setString(1, username);
			set = ps.executeQuery();
			
			if (set.next()){
				pass = set.getString("PASSWORD");
			}	
		} catch (SQLException e) {
			throw new RuntimeException("根据用户名查询密码出错",e);
		}finally{
			DBUtil.close(set, ps, conn);
		}
		return pass;
	}
}

实例工厂类:

package framework.factory;

import java.util.HashMap;
import java.util.Map;
/*
 * 实例工厂类,用于统一管理cmd、service、dao的实例。
 */
public class InstanceFactory {

	//创建一个对象池
	private static Map<String,Object> objPool = new HashMap<String, Object>();
	
	/*
	 * 根据类的包路径名称,返回该类的一个实例。
	 */
	public static <T> T getInstance(String clazz){
		
		T obj = null;
		if(objPool.containsKey(clazz)){//如果对象池中已存在,则直接从对象池中获取。
			obj = (T)objPool.get(clazz);
		}else{
			try {
				//如果对象池中不存在,则动态创建一个该类的实例,并将新创建的实例放入对象池。
				obj =  (T)Class.forName(clazz).newInstance();
				objPool.put(clazz, obj);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		return obj;
	}
}

TransactionManager 事务管理器

package framework.db;

import java.sql.Connection;
import java.sql.SQLException;

public class TransactionManager {

	private Connection con;
	private TransactionManager(Connection con){
		this.con = con;
	}
	
	/*
	 * 开启事务
	 */
	public void beginTransaction(){
		try {
			con.setAutoCommit(false);
		} catch (SQLException e) {
			throw new RuntimeException("开启事务失败!",e);
		}
	}
	/*
	 * 提交事务
	 */
	public void commitTransaction(){
		try {
			con.commit();
		} catch (SQLException e) {
			throw new RuntimeException("提交事务失败!",e);
		}finally{		
			closeConnection();
			DBUtil.threadLocalCon.remove();//将数据库连接从线程局部变量中卸载。
			}
	}
	/*
	 * 回滚事务
	 */
	public void rollbackTransaction(){
		try {
			con.rollback();
		} catch (SQLException e) {
			throw new RuntimeException("回滚事务失败!",e);
		}finally{
			closeConnection();
			DBUtil.threadLocalCon.remove();//将数据库连接从线程局部变量中卸载。
		}
	}
	/*
	 * 获取事务管理器
	 */
	public static TransactionManager getTransManager(){
		return new TransactionManager(DBUtil.getCon());
	}
	/*
	 * 关闭数据库连接,仅限事务管理器内部使用,故private
	 */
	private void closeConnection(){
		if(con != null){
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

 DBUtil ,用于获取数据库连接和关闭连接

package framework.db;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class DBUtil {

	private static String url = null;
	private static String driver = null;
	private static String username = null;
	private static String password = null;
	
	static{
		Properties p = new Properties();//加载数据源配置文件
		InputStream inputStream = null;
		try {
			inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("dataSource.properties");
			p.load(inputStream);
			url = p.getProperty("url");
			driver = p.getProperty("driver");
			username = p.getProperty("username");
			password = p.getProperty("password");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	//线程局部变量
	protected static ThreadLocal<Connection>  threadLocalCon = new ThreadLocal<Connection>();
	
	/*
	 * 获取数据库连接
	 */
	public static Connection getCon() {

		Connection con = threadLocalCon.get();
		try {
			if (con == null || con.isClosed()) {
				Class.forName(driver);
				con = DriverManager.getConnection(url, username, password);
				threadLocalCon.set(con);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return con;
	}
	
	/*
	 * 关闭结果集 ResultSet
	 */
	public static void closeResultSet(ResultSet rs){
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/*
	 * 关闭 句柄
	 */
	public static void closeStatement(Statement st){
		if(st != null){
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/*
	 * 在事务中调用dao层方法时,会首先设置事务自动提交为false,该场景下,关闭连接由事务管理器负责。
	 * 如果dao层方法没有在事务中执行,则此时事务自动提交为true,该场景下,由本方法负责关闭连接。
	 */
	public static void closeConnectionIfAutoCommit(Connection con){
		if(con != null){
		try {
			if(con.getAutoCommit()){		
				con.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	}
	/*
	 * 依次关闭ResultSet、Statement、Connection
	 */
	public static void close(ResultSet rs,Statement st,Connection con){
		closeResultSet(rs);
		closeStatement(st);
		closeConnectionIfAutoCommit(con);
	}
}

dataSource.properties配置文件

#Oracle DataSource
url=jdbc:oracle:thin:@localhost:1521:loushang
driver=oracle.jdbc.driver.OracleDriver
username=apitest
password=apitest

猜你喜欢

转载自huangqiqing123.iteye.com/blog/1404505