7.事务 连接池

事务
  事务介绍:
    就是一件事情,操作要不全部成功,要不全部失败。
    mysql里的事务操作
      通过一个命令(show variables like 'autocommit';)
        得到 autocommit=on;意思是事务 都自动提交
        每一条sql都是一个事务
      手动事务的操作:(☆)
        start transaction; 开始事务(不管是否自动提交)
        commit;提交事务
        rollback;事务回滚
      通过以下命令,可以设置事务为手动提交
        set autocommit=off;
        注意:一旦设置手动提交后,不要使用start transaction再开启事务了,这时开启的是新事务
    java里的事务操作
      Connection接口里面的方法:☆
        void setAutoCommit(boolean autoCommet):设置事务是否自动提交
        void commit():提交事务
        void rollback():事务回滚

        Savepoint setSavePoint():设置一个还原点
        void rollback(savepoint):还原到哪个还原点

public class AccountDemo {

    public static void main(String[] args)  {
        
        //aaa->bbb转钱
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Savepoint p=null;
        
        
        
        try {
            conn=JDBCUtils.getConnection();
            
            //手动开启事务
            conn.setAutoCommit(false);
            
            //先给a减钱
            String sql="update account set money =money-? where name=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "500");
            ps.setString(2, "aaa");
            int i=ps.executeUpdate();
            System.out.println(i);
            
            //设置还原点
            p=conn.setSavepoint();
            
            /*if(i==1){
                throw new RuntimeException();
            }*/
            
            //给b加钱
            sql="update account set money =money+? where name=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "500");
            ps.setString(2, "bbb");
            i=ps.executeUpdate();
            System.out.println(i);
            
        } catch (Exception e) {
            e.printStackTrace();
            //回滚事务
            try {
                conn.rollback(p);
            } catch (SQLException e1) {
                
                e1.printStackTrace();
            }
        }finally{
            //提交事务
            try {
                conn.commit();
            } catch (SQLException e) {
                
                e.printStackTrace();
            }
            
            JDBCUtils.closeResources(conn, ps, rs);
        }
        
    }

}

 


  事务的特性:(☆)
    ACID
    原子性:atomicity 要么全部成功,要么全部失败
    一致性:consistency 事务执行之后,数据库状态与其它业务规则保持一致。例如:转账,总钱数不变
    隔离性:isolation 在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
    持久性:durability 一旦事务提交或回滚后,必须持久化到数据库中
  隔离性:
    若不考虑隔离性,会出现的问题:
      脏读:读取到别的事务没有提交的数据
      不可重复读:在一个事务中,两次查询的结果不一致(内容 update)
      虚读(幻读):在一个事务中,两次查询的结果不一致(条数,针对insert delete操作)
    数据库的隔离级别:
      read uncommitted:读未提交,最低的级别,上面的情况都可以发生
      read committed:读已提交,可以避免脏读
      repeatable read:可重复读,可以避免不可重复读
      serializable:串行化,最高的等级,可以避免所有问题。
  演示几种问题:
    设置数据库的隔离级别:
      set session transactioin isolation level 级别;
    查看当前的隔离级别:
      select @@tx_isolation;
      mysql默认的隔离级别:repeatable read☆
      oracle扩展的隔离级别:read committed☆
  安全性:
    serializable>repeatable read>read committed>read uncommitted
  效率:反之


  案例:
    转账案例
    解决service层需要传入connection参数:
    Map<Thread,Connection> map

    第一次开始事务的时候,先获取map.get(Thread.currentThread()) == ThreadLocal.get()
    获取一个connection,开启事务,最后map.put(Thread.currentThread(),connection) == ThreadLocal.set()
    在dao层可以直接使用,map.get(Thread.currentThread())就可以获取绑定的链接

  执行的流程:
    account.jsp:接收用户信息
    accountServlet:接收参数,调用service,页面的跳转
    accountService:
      1.开启事务
        conn.startTransaction() ThreadLocal作用:将当前的链接和当前的线程绑定起来
      2.开始转账
      3.一旦出现异常 获取当前线程绑定的链接调用rollBack()
      4.最后,提交事务,获取当前线程绑定的链接调用commit(),然后关闭链接,最后和当前线程解绑
    accountDao:
      转入
      转出

account.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
	<h1><font color="red">${msg }</font></h1>
	<form method="post" action="${pageContext.request.contextPath }/account">
		<table border="1">
			<tr>
				<td>汇款人:</td>
				<td><input type="text" name="fromuser"></td>
			</tr>
			<tr>
				<td>收款人:</td>
				<td><input type="text" name="touser"></td>
			</tr>
			<tr>
				<td>转账金额:</td>
				<td><input type="text" name="money"></td>
			</tr>
			<tr>
				<td colspan="2"><input type="submit"></td>
			</tr>
		</table>
	 </form>
</body>
</html>

JDBCUtil:

public class JDBCUtils_ {

	static final String DRIVERCLASSNAME;
    static final String URL;
    static final String USER;
    static final String PASSWORD;
    
    static{
    	/**
		 * ResourceBundle:用于加载properties文件
		 * 	 ResourceBundle bundle=ResourceBundle.getBundle(文件名称);
		 *   通过bundle的getString(key)就可以获取指定value
		 *    String url=bundle.getString("url");
		 */
    	ResourceBundle bundle=ResourceBundle.getBundle("jdbc"); //不需要后缀名
    	DRIVERCLASSNAME=bundle.getString("driverClassName");
    	URL=bundle.getString("url");
    	USER=bundle.getString("user");
    	PASSWORD=bundle.getString("password");
    }
    
    static{
    	
    	try {
			Class.forName(DRIVERCLASSNAME);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
    
  /**
   * 获取链接
   * @return 链接
   * @throws SQLException
   */
    public static Connection getConnection() throws SQLException{
    	//第一次开启事务,先获取 
    	Connection conn=tl.get();
    	if(conn==null){
    		//创建一个
    		conn= DriverManager.getConnection(URL,USER,PASSWORD);
    		//和当前线程绑定
    		tl.set(conn);

    	}
    	return conn;
    }
    
    /**
     * 开启事务
     * @throws SQLException
     */
    public static void startTransaction() throws SQLException{
    	getConnection().setAutoCommit(false);
    }
    
    /**
     * 事务回滚
     * @throws SQLException
     */
    public static void rooBack() throws SQLException{
    	getConnection().rollback();
    }
    
    /**
     * 事务提交及关闭
     * @throws SQLException
     */
    public static void coommitAndClose() throws SQLException{
    	Connection conn=getConnection();
    	conn.commit();
    	conn.close();
    	tl.remove();//将链接移除
    }
    
    /**
     * 做增删改的时候调用
     * @param conn
     * @param st
     */
    public static void closeResources(Connection conn,Statement st){
    	
    	if(st!=null){
    		try {
				st.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();
			}
    	}
    }
    
    /**
     * 做查询时调用
     * @param conn
     * @param st
     * @param rs
     */
    public static void closeResources(Connection conn,Statement st,ResultSet rs){
    	closeResources(st,rs);
    	
    	if(conn!=null){
    		try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    
    
    public static void closeResources(Statement st,ResultSet rs){
    	if(rs!=null){
    		try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	if(st!=null){
    		try {
				st.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }

}

AccountServlet:

public class AccountServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*
		 * 接收参数
		 * 调用service
		 */
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//0.设置编码
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");  
		
		//1.接收参数
		String fromUser=request.getParameter("fromuser");
		String toUser=request.getParameter("touser");
		String money=request.getParameter("money");
		
		
		//2.调用service
		AccountService accountService=new AccountService();
		try {
			accountService.account(fromUser, toUser, money);
		} catch (MyException e) {
			e.printStackTrace();
			//添加消息,页面跳转
			request.setAttribute("msg", e.getMessage());
			request.getRequestDispatcher("/account.jsp").forward(request, response);
			return;
		}
				
		//3.页面跳转
		response.getWriter().print("转账成功");
	}
}

AccountService:

public class AccountService_ {
	
	public void  account(String fromUser,String toUser,String money){
		//开始事务
		try {
			JDBCUtils_.startTransaction();
			
			AccountDao_ accountDao=new AccountDao_();
			//出
			accountDao.accountOut( fromUser, money);
			
			//如
			accountDao.accountIn(toUser,money);
			
			
		} catch (SQLException e) {
			
			e.printStackTrace();
			
			//回滚
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				
				e1.printStackTrace();
			}
		} catch (MyException e) {
			
			e.printStackTrace();
		}finally{
			//提交
			try {
				JDBCUtils_.coommitAndClose();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

AccountDao:

public class AccountDao_ {

	public void accountOut(String fromUser, String money) throws MyException {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=JDBCUtils_.getConnection();
			String sql="upate account set money=money-? where name=?";
			ps.setString(1, money);
			ps.setString(2, fromUser);
			
			int i=ps.executeUpdate();
			if(i!=1){
				throw new MyException("转出失败");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
		}finally{
			try {
				JDBCUtils_.coommitAndClose();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void accountIn(String toUser, String money) throws MyException, SQLException {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=JDBCUtils_.getConnection();
			String sql="upate account set money=money+? where name=?";
			ps.setString(1, money);
			ps.setString(2, toUser);
			
			int i=ps.executeUpdate();
			if(i!=1){
				throw new MyException("转入失败");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally{
			JDBCUtils_.coommitAndClose();
		}
		
	}

}

Exception:

public class MyException extends Exception{

	public MyException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public MyException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public MyException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public MyException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}
}

  

 

连接池:
  连接池的优点:
    1.提高了链接的复用性
    2.节省了创建链接、销毁链接的时间,提高了性能
  规范:
    连接池都应该是DataSource的实现,datasource是一个规范,javax.sql包的一个接口
  获取链接:
    getConnection()
  关闭的时候:
    conn.close()
  常见的连接池:
    dbcp(理解):apache组织的
    c3p0(☆):c3p0
    tomcat内置的连接池(了解)
  dbcp的使用:
    1.导入jar包 commons-dbcp-1.4.jar(核心) 和commons-pool-1.5.6.jar(依赖)
    2.编写代码(两种方式)
    第一种方式:源码中配置

    第二种方式:配置文件

dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day14
username=root
password=moujinling321


DBCPDemo
public class DBCPDemo {
    public static void main(String args[]) throws Exception {
        //method1();
        method2();
    }
    
    private static void method2() throws Exception {
        /*
         * 方式二:配置文件
         */
        BasicDataSourceFactory factory=new BasicDataSourceFactory();
        Properties p=new Properties();
        p.load(new FileInputStream("src/dbcp.properties"));
        
        DataSource ds=factory.createDataSource(p); 
        
        Connection conn=ds.getConnection();
        String sql="select * from account limit 1";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
        
    }

    private static void method1() throws SQLException{
        /*
         * 方式一:源码中配置
         */
        BasicDataSource ds=new BasicDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/day14");
        ds.setUsername("root");
        ds.setPassword("moujinling321");
        
        Connection conn=ds.getConnection();
        String sql="select * from account";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
    }
}

  c3p0的使用:
    项目中使用
    自动回收空闲的链接
    使用步骤:
      1.导入jar包 c3p0-0.9.1.2.jar
      2.编码
      方式1:编码中编写配置(理解)
      方式2:配置文件

c3p0.properties
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/day14
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.user=root
c3p0.password=moujinling321


C3P0Demo
public class C3P0Demo {
    public static void main(String[] args) throws PropertyVetoException, SQLException {
        //method1();
        method2();
    }

    //第二种方式:配置文件(自动查找)
    private static void method2() throws SQLException {
        
        ComboPooledDataSource ds= new ComboPooledDataSource();
        
        Connection conn=ds.getConnection();
        String sql="select * from account limit 1";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
        
    }

    //第一种方式:源码中配置
    private static void method1() throws PropertyVetoException, SQLException {
        ComboPooledDataSource ds= new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/day14");
        ds.setUser("root");
        ds.setPassword("moujinling321");
        
        Connection conn=ds.getConnection();
        String sql="select * from account";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
    }
}

 

 

登录/注册案例:

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title>bookStore 商城-商品信息展示</title>
	</head>
	<body>
		<%@include file="/public/head.jsp" %>
		
		<%@include file="/public/menu.jsp" %>
		
		<!-- search 一行一列的表格 -->
		<div id="">
			<table width="100%" bgcolor="#B6B684">
				<tr align="right">
					<td>
						search
						<input type="text"/>
						<input type="button" value="搜索"/>      
					</td>
				</tr>
			</table>
		</div>
		
		<!-- content -->
		<div id="content">
			<table align="center" bgcolor="#FFFFF4" width="60%">
				<tr>
					<td>
						<h4>首页>>个人用户登录</h4>
						<p ><font color="red">${login_msg }</font></p>
						<!--下面整块是个table-->
						<table align="center">
							<tr>
								<td>
									<!-- 左边是table-->
									<table width="300px" bgcolor="lightgray" margin-left="10px" height="350px">
										<tr>
											<td> 
												<!--上部分是提交表单-->
												<form action="${pageContext.request.contextPath }/login" method="post">
													<table>
															<tr>
																<td colspan="2" align="center"><h3>个人用户登录</h3></td>
															</tr>
															<tr>
																<td>用户名:</td>
																<td>
																	<input type="text" name="username" value="${cookie.savename.value }"/>
																</td>
															</tr>
															<tr>
																<td>密   码:</td>
																<td>
																	<input type="password" name="password"/>
																</td>
															</tr>
															<tr>
																<td colspan="2" align="center">
																	<input type="checkbox" name="savename" value="ok"/>记住用户名
																	<input type="checkbox" name="checkbox" value="checkbox"/>自动登录
																</td>
															</tr>
															<tr>
																<td colspan="2" align="center" >
																	<input type="submit" value="登录" width="50px"/>
																</td>
															</tr>
													 </table>
												</form>
											</td>
										</tr>
										
										<tr>
											<td colspan="2">
												<hr/>
											</td>
										</tr>
										<tr>
											<td colspan="2" align="center">
												<a href="#"  style="text-decoration:none;"><h4>注册新会员</h4></a>
											</td>
										</tr>
									</table>
								</td>
								<td>
									<table>
										<tr>
											<td height="50px">
												<h4>您还没注册?</h4>
											</td>
										</tr>
										<tr>
											<td>注册新会员,享受更优惠价格!</td>
										</tr>
										<tr>
											<td height="50px">
												千种图书,供你挑选!注册即享受丰富折扣和优惠,便宜有好货!超过千万本图书任您选。
											</td>
										</tr>
										<tr>
											<td height="50px">
												超人气社区!精彩活动每一天!买卖更安心!支付宝交易超安全。
											</td>
										</tr>
										<tr>
											<td align="right" height="50px">
												<a href="#"  style="text-decoration:none;"><h4>注册新会员</h4></a>
											</td>
										</tr>
									</table>
								</td>
							</tr>
						</table>
					</td>
				</tr>
			</table>
		</div>
		
		<!-- foot 两行两列的表格-->
		<div id="foot">
			<table width="100%" bgcolor="#EFEEDC">
				<tr>
					<td rowspan="2" align="center">
						<img src="images/case1/logo.png" alt="图书商城"/>
					</td>
					<td>CONTACT US</td>
				</tr>
				<tr>
					<td>
						copyright 2008&copyrightBookStore All Rights RESERVED
					</td>
				</tr>
			</table>
		</div>
		
		<table width="100%">
			<tr>
				<td></td>
			</tr>
		</table>
	</body>
</html>

regist.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title>bookStore 商城-商品信息展示</title>
	</head>
	<body>
		<!-- head 一行两列的表格-->
		<%@include file="/public/head.jsp" %>
		
		<!-- menu 一行一列的表格-->
		<%@include file="/public/menu.jsp" %>
		
		<!-- search 一行一列的表格 -->
		<div id="search">
			<table width="100%" bgcolor="#B6B684">
				<tr align="right">
					<td>
						search
						<input type="text"/>
						<input type="button" value="搜索"/>      
					</td>
				</tr>
			</table>
		</div>
		
		<!-- content -->
		<div id="content">
			<form action="${pageContext.request.contextPath}/regist" method="post">
				<table align="center" bgcolor="#FFFFF4" width="60%">
					<tr>
						<td>
							<h1>新会员注册<font color="red">${regist_msg }</font></h1>
							<table align="center">
								<tr>
									<td align="right" >会员邮箱:</td>
									<td>
										<input type="text" name="email"/>
									</td>
									<td align="left">
										<font color="#ff0000">${map.email_msg }</font>
									</td>
								</tr>
								<tr>
									<td align="right">会员名:</td>
									<td>
										<input type="text" name="username" class="txtinput"/>
									</td>
									<td align="left">
										<font color="#ff0000"></font>
									</td>
								</tr>
								<tr>
									<td align="right">密码:</td>
									<td>
										<input type="password" name="password" class="txtinput"/>
									</td>
									<td align="left">
										<font color="#ff0000"></font>
									</td>
								</tr>
								<tr>
									<td align="right">重复密码:</td>
									<td>
										<input type="text" name="repassword"/>
									</td>
								</tr>
								<tr>
									<td align="right">性别:</td>
									<td>
										<input type="radio" name="sex" value="男"/>男
										<input type="radio" name="sex" value="女"/>女
									</td>
									<td></td>
								</tr>
								<tr>
									<td align="right">联系电话:</td>
									<td>
										<input type="text" name="telephone"/>
									</td>
								</tr>
								<tr>
									<td align="right">个人介绍:</td>
									<td>
										<input type="textarea" name="introduce"/>
									</td>
								</tr>
							</table>
							<h1>注册校验</h1>
							<table align="center" width="80%" cellspacing="2">
								<tr>
									<td align="right">输入校验码:</td>
									<td>
										<input type="text" name="checkcode" class="txtinput"/>
									</td>
									<td>${requestScope["code.msg"] }</td> <!-- code.msg,单独不可以写进去,.表示get。用域对象表示出来 -->
								</tr>
								<tr>
									<td> </td>
									<td colspan="2">
										<img src="${pageContext.request.contextPath }/code" id="imgId" alt="验证码" class="txtinput" style="height:30px"/>
										<a href="javascript:void(0)" οnclick="changeCode()">看不清?换一张</a>
										<!-- 表示这个链接不做跳转动作,执行onClick事件。 -->
									</td>
								</tr>
								<tr>
									<td align="center" colspan="3">
										<input value="同意并提交" style="background:orange;height:30px;width:100px;text-align:center;" type="submit"/>
									</td>
								</tr>
							</table>
						</td>
					</tr>
				</table>
			</form>
			
		</div>
		
		<!-- foot 两行两列的表格-->
		<div id="foot">
			<table width="100%" bgcolor="#EFEEDC">
				<tr>
					<td rowspan="2" align="center">
						<img src="images/case1/logo.png" alt="图书商城"/>
					</td>
					<td>CONTACT US</td>
				</tr>
				<tr>
					<td>
						copyright 2008&copyrightBookStore All Rights RESERVED
					</td>
				</tr>
			</table>
		</div>
		
		<table width="100%">
			<tr>
				<td></td>
			</tr>
		</table>
	</body>
<script type="text/javascript">
	function changeCode(){
		var imgObj=document.getElementById("imgId");
		imgObj.src="${pageContext.request.contextPath}/code?i="+Math.random();
	}
</script>

</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>Insert title here</title>
</head>
<body>
	<c:if test="${empty user }">
		请先<a href="${pageContext.request.contextPath }/login.jsp">登录</a>
	</c:if>
	<c:if test="${!empty user }">
		${user.username }:欢迎回来!
	</c:if>
</body>
</html> 

LoginServlet

public class LoginServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*
		 * 获取参数
		 * 调用userservice的login
		 * 页面跳转,提示信息
		 */
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		request.setCharacterEncoding("utf-8");
		
		
		//1.获取参数
		String username=request.getParameter("username");
		String password=request.getParameter("password");
		
		//2.调用service
		UserService userService=new UserService();
		User user=null;
		try {
			user = userService.login(username,password);
			if(user==null){
				 request.setAttribute("login_msg", "用户名和密码不匹配");
				 request.getRequestDispatcher("/login.jsp").forward(request, response);
				 return;
			}else{
				//登录成功
				//判断是否记住用户名 
				String savename=request.getParameter("savename");
				if(Constant.IS_SAVA_NAME.equals(savename)){
					Cookie c=new Cookie("savename",username);
					c.setMaxAge(3600);
					response.addCookie(c);
				}
			}
		} catch (UserRegistException e) {
			
			e.printStackTrace();
			//将错误信息添加到request
		    request.setAttribute("login_msg", e.getMessage());
		    request.getRequestDispatcher("/login.jsp").forward(request, response);
		} catch (SQLException e) {
			
			e.printStackTrace();
		}
		
		//3.页面跳转
		request.getSession().setAttribute("user", user);
		response.sendRedirect(request.getContextPath()+"/success.jsp");
	}
}

  UserService

public class UserService {
	UserDaoImpl userDao=new UserDaoImpl();
	/**
	 * 用户注册
	 * @param user 用户信息
	 * @throws UserRegistException 
	 */
	public void regist(User user) throws UserRegistException  {
		
		try {
			//开启事务
			DataSourceUtils.startTransaction();
			
			/*
			 * 首先判断数据库中有没有同名的
			 * 	若有,返回true,不能注册,提示信息
			 * 	若无,可以添加
			 */
			boolean flag=userDao.findUserByUsername(user);
			if(!flag){//flag=false
				
				//调用userdao的adduser方法
				userDao.addUser(user);
			}else{
				throw new UserRegistException("该用户名已被占用");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			
			try {
				DataSourceUtils.rollBack();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			throw new UserRegistException("网络异常!!");
		}finally{
			//提交事务
			try {
				DataSourceUtils.commitAndClose();
			} catch (SQLException e) {
				
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 用户登录
	 * @param username 用户名
	 * @param password 密码
	 * @return 返回用户
	 * @throws UserRegistException 
	 * @throws SQLException 
	 */
	public User login(String username, String password) throws UserRegistException, SQLException {
		User user=null;
		try {
			DataSourceUtils.startTransaction();
			user=userDao.getUserByUsernameAndPwd(username,password);
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				DataSourceUtils.rollBack();
			} catch (SQLException e1) {
				
				e1.printStackTrace();
			}
			throw e;
		}finally{
			try {
				DataSourceUtils.commitAndClose();
			} catch (SQLException e) {
				
				e.printStackTrace();
			}
		}
		
		return user;
	}

}

RegistServlet

public class RegistServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		request.setCharacterEncoding("utf-8");
		
		/*
		 * 作用:首先判断验证码
		 * 	若验证码不一致,返回错误信息(regist.jsp) 提示信息(验证码错误) request
		 * 	验证码一致,封装参数,调用userservice
		 */
		
		//1.获取验证码 
		//1.1获取页面上验证码
		String code=request.getParameter("checkcode");
		
		//1.2获取session域中的验证码
		String sessionCode=(String) request.getSession().getAttribute("session_code");
		request.getSession().removeAttribute("session_code"); //验证码一次性
		
		//2.判断验证码
		//输入验证码不正确
		if(!sessionCode.equalsIgnoreCase(code)){
			//加入错误信息,页面跳转
			request.setAttribute("code.msg", "验证码输入错误");
			request.getRequestDispatcher("/regist.jsp").forward(request,response);
			return;
		}
		
		//3.获取参数
		User user=new User();
		try {
			BeanUtils.populate(user, request.getParameterMap());
		} catch (IllegalAccessException | InvocationTargetException e) {
			
			e.printStackTrace();
		}
		//3.1数据校验
		//验证邮件
		Map<String,String> map=user.validate();
		if(map!=null && map.size()>0){
			//有错误信息
			request.setAttribute("map", map);
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
			return;
		}
		
		//4.调用userservice
		UserService userService=new UserService();
		//可能抛自定义异常
		try {
			userService.regist(user);
		} catch (UserRegistException e) {
			e.printStackTrace();
			//有异常,添加错误信息,跳转到注册页面
			request.setAttribute("regist_msg", e.getMessage());
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
		}
		
		//5.页面跳转,提示信息
		//5.1将user放到session中
		request.getSession().setAttribute("user", user);
		
		//5.2提示信息 页面跳转
		response.setHeader("refresh", "3;url="+request.getContextPath()+"/success.jsp");
		response.getWriter().print("注册成功,3秒之后跳转到首页!");
		return;
		
	}
}

  UserService

public class UserService {
	UserDaoImpl userDao=new UserDaoImpl();
	/**
	 * 用户注册
	 * @param user 用户信息
	 * @throws UserRegistException 
	 */
	public void regist(User user) throws UserRegistException  {
		
		try {
			//开启事务
			DataSourceUtils.startTransaction();
			
			/*
			 * 首先判断数据库中有没有同名的
			 * 	若有,返回true,不能注册,提示信息
			 * 	若无,可以添加
			 */
			boolean flag=userDao.findUserByUsername(user);
			if(!flag){//flag=false
				
				//调用userdao的adduser方法
				userDao.addUser(user);
			}else{
				throw new UserRegistException("该用户名已被占用");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			
			try {
				DataSourceUtils.rollBack();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			throw new UserRegistException("网络异常!!");
		}finally{
			//提交事务
			try {
				DataSourceUtils.commitAndClose();
			} catch (SQLException e) {
				
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 用户登录
	 * @param username 用户名
	 * @param password 密码
	 * @return 返回用户
	 * @throws UserRegistException 
	 * @throws SQLException 
	 */
	public User login(String username, String password) throws UserRegistException, SQLException {
		User user=null;
		try {
			DataSourceUtils.startTransaction();
			user=userDao.getUserByUsernameAndPwd(username,password);
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				DataSourceUtils.rollBack();
			} catch (SQLException e1) {
				
				e1.printStackTrace();
			}
			throw e;
		}finally{
			try {
				DataSourceUtils.commitAndClose();
			} catch (SQLException e) {
				
				e.printStackTrace();
			}
		}
		
		return user;
	}

}

  UserDao

public class UserDaoImpl implements UserDao{
	/**
	 * 添加用户
	 * @param user 用户信息
	 * @throws UserRegistException 
	 * @throws SQLException 
	 */
	public void addUser(User user) throws UserRegistException {
		//使用JDBC操作数据库
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=DataSourceUtils.getConnection();
			
			//编写sql
			//username,password,sex,telephone,email,introduce
			String sql="insert into user values(null,?,?,?,?,?,?)";
			
			//创建语句执行者
			ps=conn.prepareStatement(sql);
			//设置参数
			ps.setString(1, user.getUsername());
			ps.setString(2, user.getPassword());
			ps.setString(3, user.getSex());
			ps.setString(4, user.getTelephone());
			ps.setString(5, user.getEmail());
			ps.setString(6, user.getIntroduce());
			//执行sql
			int i=ps.executeUpdate();
			if(i==0){
				throw new UserRegistException("注册失败");
			}
			//处理结果
			System.out.println(i);
		} catch (SQLException e) {
			// 数据库异常
			e.printStackTrace();
			throw new UserRegistException("网络异常,请稍后再试");
		}finally{
			//释放资源
			DataSourceUtils.closeResources(ps, rs);
		}
	}

	/**
	 * 通过用户名查找用户
	 * 	若存在返回true
	 * 	若不存在返回false
	 */
	public boolean findUserByUsername(User user) {
		
		//使用JDBC操作数据库
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
				
		try {
			conn=DataSourceUtils.getConnection();
			String sql="select * from user where username=? limit 1";
			ps=conn.prepareStatement(sql);
			ps.setString(1, user.getUsername());
			rs=ps.executeQuery();
			return rs.next();
		} catch (SQLException e) {
		
			e.printStackTrace();
		}finally{
			DataSourceUtils.closeResources(ps, rs);
		}
		return false;
	}

	/**
	 * 通过用户名和密码获取user  登录
	 * @param username
	 * @param password
	 * @return
	 * @throws UserRegistException 
	 */
	public User getUserByUsernameAndPwd(String username, String password) throws UserRegistException {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		try {
			conn=DataSourceUtils.getConnection();
			String sql="select * from user where username=? and password =? limit 1";
			ps=conn.prepareStatement(sql);
			ps.setString(1, username);
			ps.setString(2, password);
			rs=ps.executeQuery();
			if(rs.next()){
				return new User(rs.getInt("id"),rs.getString("email"),rs.getString("username"),rs.getString("password"),rs.getString("sex"),rs.getString("introduce"), rs.getString("telephone"));
			}
			
		} catch (SQLException e) {
			
			e.printStackTrace();
			throw new UserRegistException("网络异常,请稍后再试");
		}finally{
			DataSourceUtils.closeResources(ps, rs);
		}
		return null;
	}
}

  User

public class User {
	private Integer id;
	private String email;
	private String username;
	private String password;
	private String sex;
	private String introduce;
	private String telephone;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	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 String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getIntroduce() {
		return introduce;
	}
	public void setIntroduce(String introduce) {
		this.introduce = introduce;
	}
	public String getTelephone() {
		return telephone;
	}
	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}
	public User(Integer id, String email, String username, String password, String sex, String introduce,
			String telephone) {
		super();
		this.id = id;
		this.email = email;
		this.username = username;
		this.password = password;
		this.sex = sex;
		this.introduce = introduce;
		this.telephone = telephone;
	}
	public User() {
		super();
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", email=" + email + ", username=" + username + ", password=" + password + ", sex="
				+ sex + ", introduce=" + introduce + ", telephone=" + telephone + "]";
	}
	public Map<String, String> validate() {
		//创建Map
		Map<String,String> map=new HashMap();
		
		//验证邮箱
		/*
		 * 首先验证邮箱是否为空
		 * 	若为空,提示邮箱不能为空
		 * 	若不为空,继续验证邮箱是否符合格式
		 * 		若不符合,提示邮箱格式不争取
		 * 		
		 */
		if(isNull(email)){
			map.put("email_msg", "邮箱不能为空");
		}else if(!checkEmail(email)){
			map.put("email_msg", "邮箱格式不合法");
		}
		
		return map;
	}
	
	/**
	 * 判断邮箱格式
	 * 	若符合格式,返回true
	 * 	若不符合格式,返回false
	 * @param value
	 * @return bolean
	 */
	private boolean checkEmail(String value) {
		if(value==null){
			return false;
		}
		//qwer@qq.com.cn
		String reg="^\\w+@\\w+(\\.\\w+)+$";
		return value.matches(reg);
	}
	/**
	 * 验证是否为空
	 * 	若为空返回Null
	 * 	若不为空返回false
	 * @param value
	 * @return boolean
	 */
	private boolean isNull(String value) {
		//^\s*&
		if(value==null){
			return true;
		}
		return value.matches("^\\s*$");
	}
	
}

  

转载于:https://www.cnblogs.com/syj1993/p/8440164.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值