java学生信息管理系统设计(2)
程序员文章站
2024-03-11 11:45:43
本例的学生信息添加进入数据库的事务(可以提交事务,事务回滚,用本地线程完善)
主页面index.jsp
<%@ page language="java...
本例的学生信息添加进入数据库的事务(可以提交事务,事务回滚,用本地线程完善)
主页面index.jsp
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>学生信息管理</title> </head> <body> <a href='<c:url value="/query"/>?cmd=query'>查看学生信息</a> <br><br> <!-- <a href="<c:url value='/studservlet?cmd=save' />">学生信息添加</a> --> <h2>学生信息添加</h2> <form action='<c:url value="/query"/>?cmd=add' method="post"> 姓名:<input type="text" name="name"/><br><br> <fieldset style="border: solid;border-color: red;width: 250px;"> <legend>图书1</legend> 书名:<input type="text" name="book"/><br><br> 价格:<input type="text" name="price"/> </fieldset> <br> <fieldset style="border: solid;border-color:green;width: 250px;"> <legend>图书2</legend> 书名:<input type="text" name="book"/><br><br> 价格:<input type="text" name="price"/> </fieldset> <br><br> <input type="submit" value="提交"/><br><br> </form> </body> </html>
工具包
获取数据库连接的工具connutils5.java
package cn.hncu.utils; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.sql.connection; import java.sql.drivermanager; import java.util.arraylist; import java.util.list; import java.util.properties; public class connutils5 { //本地线程管理对象,用于实现: 同一个线程获取的连接是同一个 private static threadlocal< connection> t=new threadlocal<connection>(); private final static list<connection> pool=new arraylist<connection>(); private static int size;//由资源文件读取 private connutils5(){ } static{ properties p=new properties(); try { //下面这种方式在纯java项目中可以读取到classpath下的资源文件,但无法读取javaee项目的。因为tomcat把系统的默认类加载器改了 //p.load( classloader.getsystemclassloader().getsystemresourceasstream("jdbc.properties")); // p.load(classloader.getsystemresourceasstream("jdbc.properties")); //读取web项目的classpath下的资源文件,用这个可以 p.load(connutils3.class.getclassloader().getresourceasstream("jdbc.properties")); string driver=p.getproperty("driver"); string url=p.getproperty("url"); string name=p.getproperty("username"); string pwd=p.getproperty("password"); string ssize=p.getproperty("size"); size=integer.parseint(ssize); class.forname(driver); for(int i=0;i<size;i++){ final connection con=drivermanager.getconnection(url,name,pwd); system.out.println("con=="+con); //更改conn.close()方法 //用代理模式生成一个增强版的conn对象,把它的close()方法拦截更改掉 object ncon=proxy.newproxyinstance( connutils3.class.getclassloader(), // conn.getclass().getinterfaces(), //后面这种方式不行,应该是驱动中的实现类和我们当前程序不在同一空间(类加载器不同) new class[]{connection.class}, new invocationhandler() { @override public object invoke(object proxy, method method, object[] args) throws throwable { if(method.getname().equals("close")){ system.out.println("还回一个链接:"+(connection)proxy); pool.add((connection)proxy); return null; } return method.invoke(con, args); } }); pool.add((connection)ncon); } } catch (exception e) { e.printstacktrace(); } } public static synchronized connection getconnection(){ //先从t中拿,如果有就拿出去,如果没有再到池中拿且把该对象放到t中 connection con=t.get(); if(con==null){ if(pool.size()<=0){ system.out.println("池中连接没有了..."); try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } return getconnection(); } con=pool.remove(0); t.set(con);//放到t中 } return con;//拿一个移一个 } }
代理
package cn.hncu.utils; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.sql.connection; import java.sql.sqlexception; public class txproxy implements invocationhandler { private object srcobj=null; private txproxy(object srcobj) { this.srcobj = srcobj; } public static object getproxy(object srcobj){ system.out.println("srcobj:"+srcobj); object newobj=proxy.newproxyinstance( txproxy.class.getclassloader(), srcobj.getclass().getinterfaces(), new txproxy(srcobj)); system.out.println("newobj:"+newobj); return newobj; } @override public object invoke(object proxy, method method, object[] args) throws throwable { connection con=null; object returnobj=null; try { con=connutils5.getconnection(); system.out.println("invoke拿到一个链接:"+con); con.setautocommit(false); returnobj=method.invoke(srcobj, args); system.out.println("提交一个事务..."); con.commit(); } catch (exception e) { try { system.out.println("回滚一个事务..."); con.rollback(); } catch (sqlexception e1) { e1.printstacktrace(); } }finally{ try { con.setautocommit(true); con.close(); } catch (sqlexception e) { e.printstacktrace(); } } return returnobj; } }
代理2:不需要强转,但是代理了所有
package cn.hncu.utils; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.sql.connection; import java.sql.sqlexception; public class txproxy2 implements invocationhandler { private object srcobj=null; private txproxy2(object srcobj) { this.srcobj = srcobj; } public static<t> t getproxy(class<t> c){ object obj=null; try { obj = c.newinstance(); } catch (exception e) { e.printstacktrace(); } object newobj=proxy.newproxyinstance( txproxy2.class.getclassloader(), c.getinterfaces(), new txproxy2(obj)); return (t) newobj; } @override public object invoke(object proxy, method method, object[] args) throws throwable { connection con=null; object returnobj=null; try { con=connutils5.getconnection(); system.out.println("invoke拿到一个链接:"+con); con.setautocommit(false); returnobj=method.invoke(srcobj, args); system.out.println("提交一个事务..."); con.commit(); } catch (exception e) { try { system.out.println("回滚一个事务..."); con.rollback(); } catch (sqlexception e1) { e1.printstacktrace(); } }finally{ try { con.setautocommit(true); con.close(); } catch (sqlexception e) { e.printstacktrace(); } } return returnobj; } }
注解
package cn.hncu.utils; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; @target(value=elementtype.method) @retention(retentionpolicy.runtime) public @interface transaction { }
代理3:用注解实现需要事务则用事务
package cn.hncu.utils; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.sql.connection; import java.sql.sqlexception; public class txproxy3 implements invocationhandler { private object srcobj=null; private txproxy3(object srcobj) { this.srcobj = srcobj; } public static<t> t getproxy(t srcobj){ object newobj=proxy.newproxyinstance( txproxy3.class.getclassloader(), srcobj.getclass().getinterfaces(), new txproxy3(srcobj)); return (t) newobj; } @override public object invoke(object proxy, method method, object[] args) throws throwable { /* 这种方式来实现只拦截指定的方法 if(method.getname().equals("close")){ ...拦截 }else{ return method.invoke(srcobj, args); } */ if(method.isannotationpresent(transaction.class)){ connection con=null; object returnobj=null; try { con=connutils5.getconnection(); system.out.println("invoke拿到一个链接:"+con); con.setautocommit(false); //真正的业务代码,放行 returnobj=method.invoke(srcobj, args); system.out.println("提交一个事务..."); con.commit(); } catch (exception e) { try { system.out.println("回滚一个事务..."); con.rollback(); } catch (sqlexception e1) { e1.printstacktrace(); } }finally{ try { con.setautocommit(true); con.close(); } catch (sqlexception e) { e.printstacktrace(); } } return returnobj; }else{ system.out.println("不存在事务注解,直接放行!"); return method.invoke(srcobj, args); } } }
资源文件jdbc.properties
##mysql driver=com.mysql.jdbc.driver url=jdbc:mysql://127.0.0.1:3306/hncu?useunicode=true&characterencoding=utf-8 username=root password=1234 size=3 ##oracle #driver=oracle.jdbc.driver.oracledriver #url=jdbc:oracle:thin:@127.0.0.1:1521:orcl #username=scott #password=tiger
stud层的servlet层–queryservlet.java
package cn.hncu.stud.servlet; import java.io.ioexception; import java.util.list; import java.util.map; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import cn.hncu.domain.book; import cn.hncu.domain.stud; import cn.hncu.stud.service.istudservice; import cn.hncu.stud.service.studserviceimpl; import cn.hncu.utils.txproxy3; public class queryservlet extends httpservlet { //注入 //1. // istudservice service=(istudservice) txproxy.getproxy(new studserviceimpl()); //2. // istudservice service=txproxy2.getproxy(studserviceimpl.class); //3. istudservice service=txproxy3.getproxy(new studserviceimpl()); public void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { dopost(request, response); } public void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string cmd=request.getparameter("cmd"); system.out.println("cmd:"+cmd); if("query".equals(cmd)){ query(request, response); }else if("add".equals(cmd)){ add(request, response); } } public void query(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { system.out.println("service:"+service); list<map<string, string>> studs=service.query(); request.setattribute("studs", studs); request.getrequestdispatcher("/jsps/show.jsp").forward(request, response); } public void add(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { //1收集参数 2组织参数(id字段留到dao中去补) string name[]=request.getparametervalues("name"); stud s=new stud(); s.setname(name[0]); //图书信息 string books[]=request.getparametervalues("book"); //防护一下 ---价格的防护应该也要写,这里我们偷懒了 if(books==null||books.length<=0){ return; } string prices[]=request.getparametervalues("price"); for(int i=0;i<books.length;i++){ book b=new book(); b.setname(books[i]); b.setprice(double.parsedouble(prices[i])); //※完成两个值对象的“一对多”关系的数据封装 s.getbooks().add(b);//一方 b.sets(s);//多方 } //3调用service层 try { service.save(s); } catch (exception e) { //导向失败页面 } } }
stud层的service层–
接口:
package cn.hncu.stud.service; import java.util.list; import java.util.map; import cn.hncu.domain.stud; import cn.hncu.utils.transaction; public interface istudservice { public list<map<string, string>> query(); //注意,注解只有放在接口才有用,,,,写在实现类中的方法无效(不会决定开启事务) @transaction public void save(stud stud) throws exception ; }
实现类
package cn.hncu.stud.service; import java.sql.connection; import java.sql.sqlexception; import java.util.list; import java.util.map; import cn.hncu.domain.stud; import cn.hncu.stud.dao.bookdao; import cn.hncu.stud.dao.bookjdbcdao; import cn.hncu.stud.dao.studdao; import cn.hncu.stud.dao.studjdbcdao; import cn.hncu.utils.connutils5; /*我们以后开发时通常都要采用一个dao独立操作一个表,系统中有几个实体表就写几个dao, * 以后框架都是这么干的,我们也要这样做,因为架构好! * * 采用事务的场合: * 1、如果只有一个dao,但要执行多条sql语句且涉及增删改,则要开启事务 * 2、如果一个service调用多个dao,通常也要开启事务。 */ public class studserviceimpl implements istudservice { //注入 studdao dao_stud=new studjdbcdao(); bookdao dao_book=new bookjdbcdao(); @override public list<map<string, string>> query() { return dao_stud.query(); } @override public void save(stud stud) throws exception { dao_stud.save(stud); dao_book.save(stud.getbooks()); } }
stud层的dao层–
stud接口–分离式做法,一个表对应一个dao,为框架做准备
package cn.hncu.stud.dao; import java.util.list; import java.util.map; import cn.hncu.domain.stud; public interface studdao { public list<map<string, string>> query(); public void save(stud stud) throws exception; }
stud实现类
package cn.hncu.stud.dao; import java.sql.connection; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; import java.util.arraylist; import java.util.hashmap; import java.util.list; import java.util.map; import java.util.uuid; import cn.hncu.domain.book; import cn.hncu.domain.stud; import cn.hncu.utils.connutils3; public class studjdbcdao implements studdao { @override public list<map<string, string>> query() { list<map<string, string>> list=new arraylist<map<string,string>>(); //一个map就是一行数据, list<map>就是整个数据表 connection con=null; try { con=connutils3.getconnection(); statement st=con.createstatement(); string sql="select * from stud"; resultset rs=st.executequery(sql); while(rs.next()){ map<string,string> m=new hashmap<string, string>(); m.put("id", (string) rs.getobject(1)); m.put("name", (string) rs.getobject(2)); list.add(m); } rs.close(); st.close(); } catch (sqlexception e) { e.printstacktrace(); }finally{ try { con.close(); } catch (sqlexception e) { e.printstacktrace(); } } return list; } @override public void save(stud stud) throws exception { connection con=connutils3.getconnection(); system.out.println("拿到一个链接:"+con); string sql="insert into stud values(?,?)"; string uuid=uuid.randomuuid().tostring().replace("-", ""); preparedstatement pst=con.preparestatement(sql); stud.setid(uuid);//为了"多方"即book能够拿到"一方"的id,专门补的 pst.setstring(1, uuid); pst.setstring(2, stud.getname()); system.out.println("1:"+uuid+",2:"+stud.getname()); pst.executeupdate(); // con.close();//拿到同一个con,这里就不需要关了 } }
book接口
package cn.hncu.stud.dao; import java.util.list; import cn.hncu.domain.book; public interface bookdao { public void save(list<book> books) throws exception; }
book实现类
package cn.hncu.stud.dao; import java.sql.connection; import java.sql.preparedstatement; import java.util.list; import cn.hncu.domain.book; import cn.hncu.utils.connutils3; public class bookjdbcdao implements bookdao { @override public void save(list<book> books) throws exception { connection con=connutils3.getconnection(); system.out.println("拿到一个链接:"+con); string sql="insert into book(name,price,studid) values(?,?,?)"; preparedstatement pst=con.preparestatement(sql); for(book b:books){ pst.setstring(1, b.getname()); pst.setdouble(2, b.getprice()); pst.setobject(3, "12132312");//异常(故意给一个不存在的外键字段,以测试事务回滚)--测事务回滚 // pst.setobject(3, b.gets().getid()); system.out.println("1:"+b.getname()+",2:"+b.getprice()+",3:"+b.gets().getid()); pst.addbatch();//添加到批处理 } pst.executebatch();//执行批处理 // con.close();//这里拿到同一个con,这里不需要关 } }
值对象
stud对象
package cn.hncu.domain; import java.util.arraylist; import java.util.list; /* * 一对多中的 “一”方 值对象的建法 */ public class stud { private string id; private string name; //※专为“多”方添加一个集合---体现多表中的“一对多关系” private list<book> books=new arraylist<book>();//注意,该集合要在构造时或之前就new出来。 public string getid() { return id; } public void setid(string id) { this.id = id; } public string getname() { return name; } public void setname(string name) { this.name = name; } public list<book> getbooks() { return books; } public void setbooks(list<book> books) { this.books = books; } @override public string tostring() { return "id=" + id + "," + name + "," + books; } }
book对象
package cn.hncu.domain; /* * 一对多中的 “多”方 值对象的建法 */ public class book { private integer id; //基本数据类型全部用包装类的声明,为以后使用框架做技术准备---包装类能够兼容框架(因为一般框架都会使用类反射) private string name; private double price; //※专为“一”方添加一个对象类型的变量(注意,不用studid)---体现多表中的“一对多关系” private stud s;//设置主人 //private string studid;//★★不要这样设 public integer getid() { return id; } public void setid(integer id) { this.id = id; } public string getname() { return name; } public void setname(string name) { this.name = name; } public double getprice() { return price; } public void setprice(double price) { this.price = price; } public stud gets() { return s; } public void sets(stud s) { this.s = s; } /* * 多表关联时的tostring()方法要注意一个陷阱,就是一方输出另一方,同时另一方又反过来输出前一方,形成无穷递归! */ @override public string tostring() { return "id=" + id + "," + name + "," + price;//这里不能输出stud对象,否则无穷递归 } }
显示学生信息页面jsps/show.jsp
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>学生信息管理</title> </head> <body> <h2>学生信息</h2> <c:foreach items="${studs}" var="x"> ${x.id},${x.name}<br/> </c:foreach> </body> </html>
效果图:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: PHP简单装饰器模式实现与用法示例