step1是新增作业的页面workUpdata.jsp,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用c:标签需要添加本行代码 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>workUpdate.jsp</title>
<link href="css/content.css" type="text/css" rel="stylesheet"/>
<link href="css/table.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<form action="/HomeworkSystem/ActionServlet?method=save&entityType=Work" method="post">
<div id="content_top">
作业信息更新
</div><!-- user_top end -->
<div id="content_mid">
<table class="table_theme1">
<tr>
<td>所属课程:</td>
<td>
<select name="workCourse">
<c:forEach items="${courses}" var="item">
<option value="${item.courseId}">${item.courseName}</option>
</c:forEach>
</select>
</td>
<td>作业题目:</td>
<td>
<input type="text" name="workTitle" value="${work.workTitle}"/>
</td>
</tr>
</table>
</div><!-- user_mid end -->
<div id="content_bottom">
<input type="submit" value="保存"></input>
</div><!-- "user_bottom" end -->
</form>
</body>
</html>
需要注意以下几点:
1,所属课程的<select>里面加载的课程列表,是往workUpdate.jsp页面跳转时,就携带过来的。至于如何携带的?放在ActionContext的outputParams里面不就Ok了。
2,当点击保存按钮后,表单(包含新增作业所属课程信息及作业题目信息)被提交给/HomeworkSystem/ActionServlet?method=save&entityType=Work
step2,ActionServlet只承担接受参数、返回参数的功能,具体流转交给ActionController,ActionController对method=save&entityType=Work的解析如下:
else if(context.getOperationType().equals("save")){
//注意,点击保存后,不同的实体需要携带不同的参数列表,所以采用createEntityFromRequest来创建实体
Object entity=EntityFactory.createEntityFromRequest(context.getEntityType(), request);
Map<String,Object> map=new HashMap<String,Object>();
context.setInputParams(map);
//只要是保存操作,就需要待保存的实体
map.put("waitSaveEntity", entity);
//需要根据entityId判断是新增还是修改
String id=request.getParameter("entityId");
if(id==null||"".equals(id)){
context.setEntityId(-1);
}else{
context.setEntityId(Integer.parseInt(id));
}
//因为Save之后要跳到列表,有些列表需要根据登录用户身份显示,所以
map.put("sessionUser", request.getSession().getAttribute("sessionUser"));
//------------------------------------------------------------------save work
//注意因为work是跟课程相关的,修改work后要跳转到当前课程所有作业列表,所以添加该输入项
if(context.getEntityType().equals("Work")){
map.put("courseId", request.getParameter("workCourse"));
}
需要携带的参数已经在注释里面描述的很清楚了。
step3随后,ActionController将参数传给SaveWorkAction
else if(context.getOperationType().equals("save")){
//------------------------------------------------------------------save work 需要事务
if(context.getEntityType().equals("Work")){
return new SaveWorkAction(context);
}
return new SaveAction(context);
}
step4,前面实际上都是些跳转及跳转时候需要携带的参数信息,SaveWorkAction是具体的逻辑实现如下:
package action;
import inter.IOperation;
import java.util.ArrayList;
import java.util.Date;
import database.MySQLHandler;
import operation.LessonOperation;
import operation.WorkOperation;
import servlet.ActionController;
import action.support.Action;
import action.support.ActionContext;
import entity.Lesson;
import entity.Work;
import exception.MyException;
import factory.OperationFactory;
/***
* 动作:保存作业(注意作业无法修改,都是新增,而且新增时需要事务)
* @author 猫哥
* @date 2017.2.17
*/
public class SaveWorkAction extends Action{
public SaveWorkAction(ActionContext context){
super(context);
}
@Override
public ActionContext execute() throws MyException {
//获取最大work_id,加一为新id
WorkOperation workOper=(WorkOperation)OperationFactory.createOperation("Work");
int maxId=workOper.selectMaxId();
//肯定是新增,获取新增的work信息,maxId+1是没问题的,如果正好别人插入maxId+1,大不了就失败了
Work one=(Work)context.getInputParams().get("waitSaveEntity");
one.setWorkId(maxId+1);
//待执行的sql列表
ArrayList<String> sqlList=new ArrayList<String>();
//第一条语句system_Work中新增作业
sqlList.add("insert into system_Work(work_id,Work_title,work_time,work_course)"
+" values('"+one.getWorkId()+"','"+one.getWorkTitle()+"','"+one.getWorkTime()+"','"+one.getWorkCourse().getCourseId()+"')");
//第二条语句student_job中添加多条
LessonOperation lessonOper=(LessonOperation)OperationFactory.createOperation("Lesson");
ArrayList<Lesson> lessonList=(ArrayList<Lesson>)lessonOper.selectByCourseId(one.getWorkCourse().getCourseId());
StringBuilder sqlLesson=new StringBuilder();
sqlLesson.append("insert into student_Job(Job_score,job_user,job_work) values");
for(Lesson lesson:lessonList){
String sql="('-2','"+lesson.getLessonUser().getUserId()+"','"+one.getWorkId()+"'),";
sqlLesson.append(sql);
}
sqlLesson.deleteCharAt(sqlLesson.length()-1);
if(lessonList.size()>0)
sqlList.add(sqlLesson.toString());
//执行事务
MySQLHandler hand=new MySQLHandler();
hand.doTransaction(sqlList);
//新增完毕后跳转查看作业页面
context.setOperationType("view");
Action action=ActionController.dispatchAction(context);
return action.execute();
}
}
OK,所有的关键都在hand.doTransaction(sqlList);
,这一句将sqlList中所有的sql语句按事务执行,也就是要么都执行成功,要么都完蛋不执行。
step5那么,doTransaction是如何实现的呢,如下
public Boolean doTransaction(ArrayList<String> sqlList) throws MyException{
try{
if(conn==null)//未分配
conn=MySQLPool.getConnecton();//用时从池中取,很爽快
//开始事务(不让mysql自动提交了,程序员做主何时一起提交或者还是回退)
conn.setAutoCommit(false);
for(String sql:sqlList){
stmt=conn.createStatement();
stmt.executeUpdate(sql);
}
//此处提交事务,如果中间所有执行语句没错,则全部一起执行,如果有错跳到catch
conn.commit();
return true;
}
catch (Exception ex) {
try {
//如果有错误,则回归到所有sql未执行状态
conn.rollback();
} catch (SQLException sqlEx) {
new MyException(new Date(),sqlEx.getMessage(),"事务回滚错误");
}
throw new MyException(new Date(),ex.getMessage(),"数据库执行错误");
}finally{
MySQLPool.release(conn);//用完归还
}
}
OK,到此结束,因为事务的原理上一篇讲过,此处给出实现即可。