【javaweb】自己动手实现简易的Tomcat2

一个服务器server中可以存放jd,oa这样的多个web应用;

Web应用是通过sun公司制定的servlet接口与Tomcat,JBoss等多个服务器解耦合的

所以,同一个web应用,就可以运行在多种不同的服务器上;(Tomcat,JBoss等服务器就是通过sun制定的Servlet接口来找到要执行的servlet类,从而启动web应用)

Java程序和数据库也是 JDBC接口来进行了解耦合;

Http协议的作用:

注意:

返回状态码500,就说明代码出现了问题;

 

 

项目目录

主启动类

package cn.huangyan.httpserver.core;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import cn.huangyan.httpserver.util.Logger;

/*
 * httpserver程序主入口
 * @author:huangyan
 * @version:1.0
 * */ 
public class BootStrap {

	public static void main(String[] args) {
		start();
	}

	// 主程序入口
	public static void start() {
		ServerSocket serverSocket = null;
		BufferedReader br = null;
		Socket clientSocket = null;
		try {
			Logger.log("httpserver start");
			
			// 获取当前时间
			long startTime = System.currentTimeMillis();
			
			// 解析服务器中包含的所有web.xml配置文件
			String[] webAppNames = {"oa"};
			WebParser.parser(webAppNames);
			
			
			// 获取系统端口号
			int port = ServerParser.getPort();
			Logger.log("httpserver-port:"+port);
			
			serverSocket = new ServerSocket(port);
			
			// 获取结束时间
			long endTime = System.currentTimeMillis();
			Logger.log("httpserver started:" + (endTime - startTime) + " ms");
			
			// 通过while循环,让服务器一直处理监听状态
			while(true) {
				
				// 开始监听
				clientSocket = serverSocket.accept();
				
				// 每一次请求,都开启一个新的线程进行请求处理
				new Thread(new HandlerRequest(clientSocket)).start();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(serverSocket != null) {
				try {
					serverSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

}

a)主线程负责接收每个客户端socket,并为每个客户端socket创建一个子线程负责处理

b)解析服务器中包含的所有web.xml配置文件

c)扫描配置文件server.xml,获取系统端口号

conf/server.xml

<?xml version="1.0" encoding="UTF-8"?>
<server>
	<service>
		<connector port="8080"></connector>
	</service>
</server>

 

package cn.huangyan.httpserver.core;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/*
 * 解析服务器中的web.xml配置文件
 * */
public class WebParser {
	
	public static  Map<String, Map<String,String>> servletMaps = new HashMap<String,  Map<String,String>>();
	
	/*
	 * 解析服务器中所有web应用的web.xml
	 * */
	public static void parser(String[] webAppNames) throws DocumentException{
		for(String webAppName : webAppNames) {
			Map<String,String> servletMap = parser(webAppName);
			
			servletMaps.put(webAppName, servletMap);
		}
	}

	
	/*
	 * 解析单个应用的web.xml配置文件
	 * */
	private static Map<String,String> parser(String webAppName) throws DocumentException{
		// 获取web.xml的路径
		String webPath = webAppName + "/WEB-INF/web.xml"; // sun公司规定的路径,没有为什么;    实现web服务器和app解耦

		// 创建xml解析器
		SAXReader saxReader = new SAXReader();

		Document document = saxReader.read(new File(webPath));

		// 获取servlet节点元素
		List<Element> servletNodes = document.selectNodes("/web-app/servlet");
		
		// 创建一个servletInfoMap集合:将servlet-name和servlet-class当做key和value存入此Map中
		Map<String,String> servletInfoMap = new HashMap<String, String>();

		// 开始遍历servletNodes
		for(Element servletNode : servletNodes) {
			// 获取servlet-name节点元素
			Element servletNameEle = (Element) servletNode.selectSingleNode("servlet-name");
			// 获取servlet-name节点元素对象的值
			String servletName = servletNameEle.getStringValue();

			// 获取servlet-class节点元素
			Element servletClassEle = (Element) servletNode.selectSingleNode("servlet-class");
			// 获取servlet-class节点元素对象的值
			String servletClassName = servletClassEle.getStringValue();

			// 将servletName和servletClassName作为key/value,放入servletInfoMap集合中
			servletInfoMap.put(servletName, servletClassName);
		}

		// 获取servlet节点元素
		List<Element> servletMappingNodes = document.selectNodes("/web-app/servlet-mapping");
		// 创建一个servletInfoMap集合:将servlet-name和url,当做key和value存入此Map中
		Map<String,String> servletMappingInfoMap = new HashMap<String, String>();

		// 开始遍历servletMappingNodes
		for(Element servletMappingNode : servletMappingNodes) {
			Element servletNameEle = (Element) servletMappingNode.selectSingleNode("servlet-name");
			String servletName = servletNameEle.getStringValue();

			Element urlPatternEle = (Element) servletMappingNode.selectSingleNode("url-pattern");
			String urlPattern = urlPatternEle.getStringValue();
			
			// 这里要替换为servletMappingInfoMap,不要再写成servletInfoMap
			servletMappingInfoMap.put(servletName, urlPattern);
		}
		
		
		// 获取servletInfoMap的keySet()
		Set<String> servletNames = servletInfoMap.keySet();
		
		// 创建一个servletMap:
		// 将servletMappingInfoMap的value与servletInfoMap的value,分别作为key与value存入此servletMap
		Map<String,String> servletMap = new HashMap<String, String>();
		for(String servletName : servletNames) {
			String urlPattern = servletMappingInfoMap.get(servletName);
			String servletClassName = servletInfoMap.get(servletName);
			
			servletMap.put(urlPattern, servletClassName);
		}
		
		return servletMap;
	}
}

 

考虑使用web.xml配置文件的原因:(解耦合)

Sun公司制定了规范;

Sun公司规定了webapp开发人员必须把web.xml放在规定的位置,必须使用规定的标签来描述url和类名之间的映射关系

Sun公司也规定了web服务器开发人员,就去这里读取web.xml,并读取web.xml中的规定的标签;

从而,实现了webapp开发人员和web服务器开发人员的解耦合

a)使用SAXReader,并使用三个Map,读取web.xml,最终将一个web.xml中的所有urlPattern <--> servletClassName保存进入ServletMap中

解析server.xml配置文件的类

package cn.huangyan.httpserver.core;

import java.io.File;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/*
 * 解析server.xml配置文件
 * */
public class ServerParser {

	/*
	 * 获取服务器的端口号
	 * @return int port
	 * */
	public static  int getPort() {
		
		// 设置服务器默认启动端口
		int port = 8080;
		
		try {
			// 创建解析器
			SAXReader saxReader = new SAXReader();
			
			// 通过解析器的read方法,将配置文件读取到内存中,生成一个Document[org.dom4j]对象树
			//Document document = saxReader.read("D:\\ecli_space\\workspace\\myday06\\src\\main\\resources\\conf\\server.xml");
			//Document document = saxReader.read("src/main/resources/conf/server.xml");
			/*
			 * File用在web项目中,路径最前面不以/开头时,则是以当前web项目为根目录
			 * */
			Document document = saxReader.read(new File("src/main/resources/conf/server.xml"));
			
			// 获取connector节点的路径:server -> service -> connector
			// 获取connector节点的xpath路径:/server/service/connector
			// 获取connector节点的xpath路径:server//connector
			// 获取connector节点的xpath路径://connector
			Element connectorEle = (Element) document.selectSingleNode("//connector");
			
			// 获取port属性的值
			port = Integer.parseInt(connectorEle.attributeValue("port"));
			
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		
		return port;
	}
}

a)涉及到File类在javaweb项目中,读取文件时路径书写的用法

 

客户端请求处理类

package cn.huangyan.httpserver.core;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Map;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;

import org.huangyan.oa.servlet.LoginServlet;

import cn.huangyan.httpserver.util.Logger;

/*
 * 处理客户端请求
 * @version 1.0
 * @since 1.0
 * */
public class HandlerRequest implements Runnable {
	public Socket clientSocket;
	public HandlerRequest(Socket clientSocket) {
		this.clientSocket = clientSocket;
	}

	@Override
	public void run() {
		// 处理客户端请求

		BufferedReader br = null;
		Logger.log("httpserver thread: "+ Thread.currentThread().getName());;

		PrintWriter out = null;

		// 接收客户端消息
		try {
			br = new BufferedReader(new	InputStreamReader(clientSocket.getInputStream()));

			// 获取响应流对象
			out = new PrintWriter(clientSocket.getOutputStream());

			/*
			// 打印出全部,请求协议
			 * String temp = null; while((temp = br.readLine()) != null) {
			 * System.out.println(temp); }
			 */

			String requestLine = br.readLine(); // GET /oa/index.html HTTP/1.1
			String requestURI = requestLine.split(" ")[1];
			System.out.println("reqeustURI="+requestURI);

			// 判断用户请求是否为静态页面:以.html或者.htm后缀名的文件叫做HTML静态页面
			if(requestURI.endsWith(".html") || requestURI.endsWith(".htm")) {
				//处理静态页面的方法
				responseStaticPage(requestURI,out);
			}else {
				// 动态资源:java程序,业务处理类

				// requestURI:/oa/login?username=jack&password=123
				String servletPath = requestURI;
				if(servletPath.contains("?")) {
					servletPath = servletPath.split("\\?")[0]; // servletPath.split("[?]")[0]
				}
				System.out.println("servletPath="+servletPath);
				
				/*
				 * // 这里请求路径和LoginServlet在服务器程序中耦合了
				 *  if("/oa/login".equals(servletPath)) {
				 * 		LoginServlet loginServlet = new LoginServlet(); 
				 * 		loginServlet.service();
				 *  }
				 */

				// 获取应用的名称webAppName
				// webAppName: oa,在URI中:/oa/login
				String webAppName = servletPath.split("[/]")[1];
				System.out.println("webAppName="+webAppName); // oa
				
				// 获取servletMaps集合中的value值
				Map<String,String> servletMap = WebParser.servletMaps.get(webAppName);

				// 从uri:/oa/login 中获取到:/login
				String urlPattern = servletPath.substring(1+webAppName.length());

				String servletClassName = servletMap.get(urlPattern);

				try {
					if(servletClassName != null) {
						// 如果找到了动态资源
						
						// 封装请求对象
						ServletRequest request = new RequestObject(requestURI);
						
						// 封装响应对象
						ResponseObject response = new ResponseObject();
						response.setWriter(out);
						
						// 拼接响应信息
						out.print("HTTP/1.1 200 OK\n");
						out.print("Content-Type:text/html;charset=utf-8\n\n");
						
						
						/*
						 * 创建Servlet对象之前,先从Servlet缓存池中查找
						 * 1. 有,直接拿来用
						 * 2. 没有,创建Servlet对象,并放入缓存池中
						 * */
						Servlet servlet = ServletCache.get(urlPattern);
						if(servlet == null) {
							Class clazz = Class.forName(servletClassName);
							Object obj = clazz.newInstance();
							
							servlet = (Servlet)obj;
							
							// 将创建好的Servlet放入缓存池中
							ServletCache.put(urlPattern, servlet);
						}
						
						
						/*
						 * 服务器将out输出流对象,传递给webapp开发人员使用的service方法
						 * 从而webapp开发人员便可以拿着此out输出流对象,往页面写一些数据
						 * 
						 * 由于当前线程持有的是此out输出流对象
						 * 我们为了保证同处于当前线程的service()业务方法,也持有同样的out输出流对象,
						 * 则必须把此out输出流对象传递给service方法,而不能自己去service()业务方法中去new一个新的out对象
						 * 
						 * servlet.service(out);
						 * */
						
						Logger.log("Servlet对象是:"+servlet);
						// 这个时候,服务器开发人员不知道如何调用servlet业务处理类里的业务方法
						// 这个时候,sun公司的servlet规范又出来了
						servlet.service(request,response);
						
					}else {
						// 404找不到动态资源
						StringBuilder html = new StringBuilder();
						html.append("HTTP/1.1 404 NotFound\n");
						html.append("Content-Type:text/html;charset=utf-8\n\n");
						html.append("<html>\r\n" + 	"<head>\r\n" + 	"<meta charset=\"UTF-8\">\r\n" + 
								"<title>404-错误</title>\r\n" + "</head>\r\n" + 
								"<body>\r\n" + 	"<center><font size=\"35xp\" color=\"red\">404-Not-Found</font></center>\r\n" + 
								"</body>\r\n" + "</html>");

						out.print(html);
					}
					
				} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
					e.printStackTrace();
				}

			}

			// 强制刷新(否则,浏览器无法显示)
			out.flush();

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(clientSocket != null) {
				try {
					clientSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	/* 处理静态页面
	 * requestURI 
	 * */
	public void responseStaticPage(String requestURI, PrintWriter out) {
		// requestURI: /oa/index.html
		// 静态页面路径:oa/index.html
		String htmlPath = requestURI.substring(1);

		BufferedReader br = null;

		try {
			// 读取页面
			br = new BufferedReader(new FileReader(htmlPath));
			String temp = null;
			StringBuilder html = new StringBuilder();

			// 拼接响应信息
			html.append("HTTP/1.1 200 OK\n");
			html.append("Content-Type:text/html;charset=utf-8\n\n");
			while((temp = br.readLine()) != null) {
				html.append(temp);
			}

			// 输出HTML
			out.print(html);

		} catch (FileNotFoundException e) {
			// 404找不到静态资源
			StringBuilder html = new StringBuilder();
			html.append("HTTP/1.1 404 NotFound\n");
			html.append("Content-Type:text/html;charset=utf-8\n\n");
			html.append("<html>\r\n" + 	"<head>\r\n" + 	"<meta charset=\"UTF-8\">\r\n" + 
					"<title>404-错误</title>\r\n" + "</head>\r\n" + 
					"<body>\r\n" + 	"<center><font size=\"35xp\" color=\"red\">404-Not-Found</font></center>\r\n" + 
					"</body>\r\n" + "</html>");

			out.print(html);
		}catch(IOException e) {
			e.printStackTrace();
		}


	}

}

a)客户端请求处理类又细分为两个部分:处理静态资源,处理请求的动态资源

b)如果处理的请求是请求动态资源,则涉及到在服务器代码中封装请求对象,封装响应对象,servlet缓存池

c)引出sun公司定义javax.servlet.Servlet接口的目的

Servlet缓存池

package cn.huangyan.httpserver.core;

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

import javax.servlet.Servlet;

/*
 * Servlet缓存池
 * */
public class ServletCache {

	private static Map<String,Servlet> servletMap = new HashMap<String,Servlet>();
	
	public static void put(String urlPattern , Servlet servlet) {
		servletMap.put(urlPattern, servlet);
	}
	
	public static Servlet get(String urlPattern) {
		return servletMap.get(urlPattern);
	}
}

javax.servlet.Servlet接口

package javax.servlet;

/*
 * 由sun公司指定的servlet接口规范,
 * 该接口由web服务器开发人员调用,由webapp开发人员来实现;
 * */
public interface Servlet {

	// 业务处理方法
	void service(ServletRequest request,ServletResponse response);
	
}

/*
 * import cn.huangyan.httpserver.core.ResponseObject;  
 * // 这个又出现一个问题,此ResponseObject是web服务器开发人员开发程序是自定义的
 * 
 * 
 * 由sun公司指定的servlet接口规范, 
  
  public interface Servlet {
      void service(ResponseObject response); 
  }
  
  	----------  这就出现了耦合的问题:
  	在sun公司开发的接口中出现了比如Tomcat公司自定义的ResponseObject类
  	----------  这时,就需要把sun公司和Tomcat公司再通过接口进行解耦合
  	定义ServletResponse接口
  	
 */

a)在sun公司的Servlet接口中出现了Tomcat公司自定义的Response类,这就又出现了耦合的问题

b)sun公司为了消除这种耦合,就又定义了ServletRequest接口和ServletResponse接口

请求对象接口

package javax.servlet;

/*
 * 负责封装请求参数的对象
 * */
public interface ServletRequest {
	
	// 获取单选框标参数的值
	public String getParametervalue(String key);

	// 获取多选框标参数的值
	public String[] getParametervalues(String key);
}

响应对象接口

package javax.servlet;

import java.io.PrintWriter;

/*
 * sun公司定义的:
 *   封装响应参数的接口规范
 * */
public interface ServletResponse {

	void setWriter(PrintWriter out);
	
	PrintWriter getWriter();
}

 

工具类

日期工具类

package cn.huangyan.httpserver.util;

import java.text.SimpleDateFormat;
import java.util.Date;

/* 日期工具类
 * @author huangyan
 * @version 1.0
 * #since 1.0
 * */
public class DateUtil {
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
	private DateUtil() {}
	
	/*
	 * 获取系统当前时间
	 * @return String [yyyy-MM-dd HH:mm:ss SSS]
	 * */
	public static String getCurrentTime() {
		return dateFormat.format(new Date());
	}
}

日志工具类

package cn.huangyan.httpserver.util;

import java.text.SimpleDateFormat;
import java.util.Date;

/*
 * 日志记录器
 * @author:huangyan
 * @version:1.0
 * */
public class Logger {
	
	// 工具类的方法往往是静态的,直接通过类名来调用,不需要创建对象;
	
	// 工具类的构造方法往往是私有的,但不是必须的;
	private Logger() {
		
	}
	
	public static void log(String msg) {
		/*
		 * SimpleDateFormat dataFormat = new
		 * SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); Date nowTime = new Date();
		 * String nowTimeStr = dataFormat.format(nowTime);
		 */
		System.out.println("[INFO] "+DateUtil.getCurrentTime()+" "+msg);
	}
}

 

业务处理类

登录的业务处理类

package org.huangyan.oa.servlet;

import java.io.PrintWriter;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import cn.huangyan.httpserver.core.ResponseObject;

/*
 * 处理登录业务的java程序
 * 该java程序由webapp开发人员编写;由web服务器来调用
 * */
public class LoginServlet implements Servlet{

	@Override
	public void service(ServletRequest request,ServletResponse response) {
		System.out.println("login-service:正在执行身份验证...");	

		// 获取当前线程的输出流对象(也就是当前客户端socket对象对应的输出流对象)
		PrintWriter out = response.getWriter();

		out.append("<html>\r\n" + 	"<head>\r\n" + 	"<meta charset=\"UTF-8\">\r\n" + 
				"<title>404-错误</title>\r\n" + "</head>\r\n" + 
				"<body>\r\n" + 	"<center><font size=\"35xp\" color=\"blue\">正在执行身份验证...</font></center>\r\n" + 
				"</body>\r\n" + "</html>");

	}

	/*
	 * @Override public void service(ResponseObject response) {
	 * System.out.println("login-service:正在执行身份验证...");
	 * 
	 * // 获取当前线程的输出流对象(也就是当前客户端socket对象对应的输出流对象) PrintWriter out =
	 * response.getWriter();
	 * 
	 * out.append("<html>\r\n" + "<head>\r\n" + "<meta charset=\"UTF-8\">\r\n" +
	 * "<title>404-错误</title>\r\n" + "</head>\r\n" + "<body>\r\n" +
	 * "<center><font size=\"35xp\" color=\"blue\">正在执行身份验证...</font></center>\r\n"
	 * + "</body>\r\n" + "</html>"); }
	 */
}

用户保存的业务处理类

package org.huangyan.oa.servlet;

import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/*
 * 处理登录业务的java程序
 * 该java程序由webapp开发人员编写;由web服务器来调用
 * */
public class UserSaveServlet implements Servlet{

	@Override
	public void service(ServletRequest request,ServletResponse response ) {
		System.out.println("UserSaveServlet:正在执行用户保存");	
		
		String username = null;
		try {
			// 对传递过来的“%e6%96%b0%e5%bb%ba”,这种UTF-8编码的串,用UTF-8进行解码
			username = URLDecoder.decode(request.getParametervalue("username"),"UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String gender = request.getParametervalue("gender");
		String[] likes = request.getParametervalues("like");
		
		System.out.println("username="+username);
		
		PrintWriter out = response.getWriter();
		out.print("<html>\r\n" + 	"<head>\r\n" + 	"<meta charset=\"UTF-8\">\r\n" + 
				"<title>用户信息</title>\r\n" + "</head>\r\n" + 	"<body>\r\n"
				+"用户名:"+username+ "<br>"
				+"性别:"+gender+ "<br>"
				+"爱好:"+likes[0]+" "+likes[1]+
				"</body>\r\n" + "</html>");
		
	}
	
//	public void service(ResponseObject response) {
//		System.out.println("UserSaveServlet:正在执行用户保存");		
//	}
}

web应用:oa

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>oa办公系统</title>
</head>
<body>
	<center><font size="35xp" color="blue">oa办公系统首页</font></center>
</body>
</html>

userSave.html

<!DOCTYPE html>
<html>
<head>
	<title>用户信息-保存用户信息</title>
	<meta content="text/html;charset=utf-8">
</head>
<body>
	<center>
		<form name="userForm" action="/oa/user/save" method="get">
			用户名:
				<input type="text" name="username"/><br><br>
				
			性&nbsp;&nbsp;别:
				<input type="radio" name="gender" value="1"/>男
				<input type="radio" name="gender" value="0"/>女
				<br><br>
				
			性&nbsp;&nbsp;别:
				<input type="checkbox" name="like" value="music"/>音乐
				<input type="checkbox" name="like" value="sport"/>运动
				<input type="checkbox" name="like" value="food"/>美食
				<input type="checkbox" name="like" value="sleep"/>睡觉
				<input type="checkbox" name="like" value="travel"/>旅行
				<br><br>
			
				<input type="submit" value="提交"/>
				<input type="reset" value="重置"/>
		</form>
	</center>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	
	<servlet>
		<servlet-name>LoginServlet</servlet-name>
		<servlet-class>org.huangyan.oa.servlet.LoginServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>LoginServlet</servlet-name>
		<url-pattern>/login</url-pattern>
	</servlet-mapping>
	
	
	<servlet>
		<servlet-name>UserSaveServlet</servlet-name>
		<servlet-class>org.huangyan.oa.servlet.UserSaveServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>UserSaveServlet</servlet-name>
		<url-pattern>/user/save</url-pattern>
	</servlet-mapping>
	
</web-app>

web应用:bank

actOpen.html

<html>
	<head>
		<title>银行帐户-开户</title>
		<meta content="text/html;charset=utf-8"/>
	</head>
	<body>
		<form name="actOpenForm" action="/bank/act/open" method="get">
			银行帐户:
				<input type="text" name="actno"/>
				<br><br>
			开户金额:
				<input type="text" name="balance"/>
				<br><br>
				<input type="submit" value="确认开户"/>
				<input type="reset" value="重置"/>
		</form>
	</body>
</html>

actTransfer.html

<html>
	<head>
		<title>银行帐户-转帐</title>
		<meta content="text/html;charset=utf-8"/>
	</head>
	<body>
		<form name="actTransferForm" action="/bank/act/transfer" method="get">
			转出帐号:
				<input type="text" name="actFrom"/>
				<br><br>
			转出金额:
				<input type="text" name="balance"/>
				<br><br>
			转入帐号:
				<input type="text" name="actTo"/>
				<br><br>
				<input type="submit" value="确认转帐"/>
				<input type="reset" value="重置"/>
		</form>
	</body>	
</html>

web.xml

<?xml version="1.0"	encoding="UTF-8"?>
<web-app>
	<servlet>
		<servlet-name>actOpenServlet</servlet-name>
		<servlet-class>org.bjpowernode.bank.servlet.ActOpenServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>actOpenServlet</servlet-name>
		<url-pattern>/act/open</url-pattern>
	</servlet-mapping>
	
	<servlet>
		<servlet-name>actTransferServlet</servlet-name>
		<servlet-class>org.bjpowernode.bank.servlet.ActTransferServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>actTransferServlet</servlet-name>
		<url-pattern>/act/transfer</url-pattern>
	</servlet-mapping>
</web-app>

开户的业务处理类

package org.bjpowernode.bank.servlet;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class ActOpenServlet implements Servlet {

	@Override
	public void service(ServletRequest request, ServletResponse response) {
		//-----------从页面获取参数值------------
		String actno = request.getParameterValue("actno");
		double balance = Double.parseDouble(request.getParameterValue("balance"));
		
		//---------------连接数据库-------------
		Connection conn = null;
		PreparedStatement ps = null;
		int count = 0;
		try {
			//1.注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.获取数据库连接对象
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3366/bjpowernode", "root", "111");
			//3.定义SQL语句框架
			String sql = "insert into t_act(actno,balance) values(?,?)";
			//4.进行SQL语句预编译
			ps = conn.prepareStatement(sql);
			//5.进行赋值
			ps.setString(1, actno);
			ps.setDouble(2, balance);
			//6.执行SQL语句
			count = ps.executeUpdate();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			//关闭资源
			if(ps != null){
				try {
					ps.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn != null){
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		//获取响应流对象
		PrintWriter out = response.getWriter();
		if(count == 1){
			out.print("<html>");
			out.print("<head>");
			out.print("<title>银行帐户-开户结果</title>");
			out.print("<meta content='text/html;charset=utf-8'/>");
			out.print("</head>");
			out.print("<body>");
			out.print("<center><font size='35px' color='green'>恭喜您,开户成功!</font></center>");
			out.print("</body>");
			out.print("</html>");
		}else{
			out.print("<html>");
			out.print("<head>");
			out.print("<title>银行帐户-开户结果</title>");
			out.print("<meta content='text/html;charset=utf-8'/>");
			out.print("</head>");
			out.print("<body>");
			out.print("<center><font size='35px' color='red'>对不起,开户失败!</font></center>");
			out.print("</body>");
			out.print("</html>");
			
		}
	}

}

转账的业务处理类

package org.bjpowernode.bank.servlet;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class ActTransferServlet implements Servlet {

	@Override
	public void service(ServletRequest request, ServletResponse response) {
		//------------获取页面请求的参数------------
		String actFrom = request.getParameterValue("actFrom");
		double balance = Double.parseDouble(request.getParameterValue("balance"));
		String actTo = request.getParameterValue("actTo");
		
		//-----------连接数据库---------------
		Connection conn = null;
		PreparedStatement ps = null;
		int count = 0;
		try {
			//1.注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.获取数据库连接
			String url = "jdbc:mysql://127.0.0.1:3366/bjpowernode";
			String user = "root";
			String password = "111";
			conn = DriverManager.getConnection(url, user, password);
			
			//开启事务,关闭自动提交
			conn.setAutoCommit(false);
			
			//3.定义SQL语句框架
			String sql_from = "update t_act set balance = balance - ? where actno = ?";
			//4.进行SQL语句的预编译
			ps = conn.prepareStatement(sql_from);
			//5.进行赋值
			ps.setDouble(1, balance);
			ps.setString(2, actFrom);
			//6.执行SQL语句
			count = ps.executeUpdate();
			
			
			String sql_to = "update t_act set balance = balance + ? where actno = ?";
			ps = conn.prepareStatement(sql_to);
			ps.setDouble(1, balance);
			ps.setString(2, actTo);
			count = count + ps.executeUpdate();
			
			//提交事务
			conn.commit();
		} catch (Exception e) {
			try {
				// 出现异常,则进行事务回滚
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}finally{
			//关闭资源
			if(ps != null){
				try {
					ps.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn != null){
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		//获取响应流对象
		PrintWriter out = response.getWriter();
		if(count == 2){
			out.print("<html>");
			out.print("<head>");
			out.print("<title>银行帐户-转帐结果</title>");
			out.print("<meta content='text/html;charset=utf-8'/>");
			out.print("</head>");
			out.print("<body>");
			out.print("<center><font size='35px' color='green'>转帐成功!</font></center>");
			out.print("</body>");
			out.print("</html>");
		}else{
			out.print("<html>");
			out.print("<head>");
			out.print("<title>银行帐户-转帐结果</title>");
			out.print("<meta content='text/html;charset=utf-8'/>");
			out.print("</head>");
			out.print("<body>");
			out.print("<center><font size='35px' color='red'>转帐失败!</font></center>");
			out.print("</body>");
			out.print("</html>");
			
		}
	}

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值