上次只发了一半,今天接着上次的内容发给大家来看,呵呵希望会有所帮助。
l
构建
Ibatis
的配置文件和映射文件
(
详细讲解请参考
ibatis
开发指南
)
(1)
配置文件
代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
lazyLoadingEnabled="true" maxRequests="32" maxSessions="10"
maxTransactions="5" useStatementNamespaces="false" />
<typeAlias alias="user" type="com.sample.domain.User" />
<typeAlias alias="article" type="com.sample.domain.Article" />
<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL"
value="jdbc:mysql://localhost:3306/sample" />
<property name="JDBC.Username" value="root" />
<property name="JDBC.Password" value="root" />
</dataSource>
</transactionManager>
<sqlMap resource="com/sample/dao/impl/User.xml" />
<sqlMap resource="com/sample/dao/impl/Article.xml" />
</sqlMapConfig>
(2) SQL Map
映射文件
User.xml
文件代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="User">
<insert id="addUser" parameterClass="user">
<!--
把
sql
语句放在
cdata
段里,避免因特殊字符出现而遇到问题
-->
<![CDATA[
insert into user (logon_name, nick_name, password) values (#logonName#, #nickName#, #password#)
]]>
<selectKey keyProperty="id">
select last_insert_id()
</selectKey>
</insert>
<select id="getUserById" resultClass="user" parameterClass="int">
<![CDATA[
select
id as id,
logon_name as logonName,
nick_name as nickName,
password as password
from user where id=#val#
]]>
</select>
<select id="getUserByLogonName" resultClass="user" parameterClass="string">
<![CDATA[
select
id as id,
logon_name as logonName,
nick_name as nickName,
password as password
from user where logon_name=#val#
]]>
</select>
<select id="getUserByLogonNameAndPassword" resultClass="user" parameterClass="user">
<![CDATA[
select
id as id,
logon_name as logonName,
nick_name as nickName,
password as password
from user where logon_name=#logonName# and password=#password#
]]>
</select>
</sqlMap>
Article.xml
与
User.xml
不能具有同名的
id
如果有的话需要设置名称空间。
Article.xml
配置类似
User.xml
代码略。
l
ArticleServiceTest
该类也是一个
junit
测试类,用来测试对帖子的增、删、改、查的各个方法。代码如下:
public class ArticleServiceTest extends TestCase {
ArticleService articleService;
UserService userService;
public ArticleServiceTest(String arg0) {
super(arg0);
articleService = new ArticleServiceImpl(new ArticleDaoIbatisImpl());
userService = new UserServiceImpl(new UserDaoIbatisImpl());
}
/**
*
此方法模拟用户注册
->
发贴的流程。帖子内容在方法内部使用硬编码产生。
* @param post
帖子后缀(防止出现重复)
* @param parentid
如果是跟贴,则设置所属主贴的
id
。
* @return
发出的帖子(
Article
的对象)
*/
private Article addArticle(String post, int parentId) {
//
生成一个新的用户
User user = new User();
user.setLogonName("logonName1" + post);
user.setNickName("nickName1" + post);
user.setPassword("password" + post);
//
注册该用户
this.userService.regist(user);
/**
生成一篇新的文章,
*
并设置标题、内容、所属主贴、发贴日期
*
将新注册的用户设为发帖人
*/
Article art = new Article();
art.setTitle("title" + post);
art.setContent("content" + post);
art.setParentId(parentId);
art.setIssue(new Date());
art.setAuthor(user);
this.articleService.addArticle(art);
return art;
}
//
测试添加发贴是否成功
public void testAddArticle() {
Article art = this.addArticle("1", 0);
assertTrue(art.getId() > 0);
}
public void testGetArticleById() {
Article art = this.addArticle("2", 0);
Article a = this.articleService.getArticleById(art.getId());
assertEquals(art.getTitle(), a.getTitle());
}
//
测试删除帖子的方法
public void testDelArticle() {
Article art = this.addArticle("3", 0);
this.articleService.delArticle(art.getId(), art.getAuthor());
Article a = this.articleService.getArticleById(art.getId());
assertNull(a);
}
public void testUpdateArticle() {
Article art = this.addArticle("4", 0);
art.setTitle("new title");
art.setContent("new content");
this.articleService.updateArticle(art, art.getAuthor());
Article a = this.articleService.getArticleById(art.getId());
assertEquals(art.getTitle(), a.getTitle());
assertEquals(art.getContent(), a.getContent());
}
//
测试跟贴
public void testGetChildrenArticles() {
Article art = this.addArticle("5", 0);
this.addArticle("6", art.getId());
this.addArticle("7", art.getId());
this.addArticle("8", art.getId());
List<Article> arts = this.articleService.getChildrenArticles(art
.getId());
assertEquals(3, arts.size());
}
}
小型BBS二
上次主要是针对业务逻辑层和数据访问层,以下主要就是设计和实现
WEB
层(采用
Struts
框架)
1. Struts
的优缺点
缺点:它与
formbean
以及
jsp
绑定太紧密了。
它的标签比较复杂。
优点:它是最简单的
MVC
设计模式,而且文档比较全。这也是它比
WebWork
应用更广泛的原因之一。
2. Struts
环境的搭建
导入必须的
jar
包
3. WEB
层的开发
l
配置文件
struts-config.xml
是整个
Struts
的核心。代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<!-- <global-exceptions>
<exception key="expired.password"
type="cn.pf.tbbs.exception.DataAccessException"
path="/WEB-INF/jsp/comm/DataAccessException.jsp">
</exception>
<exception key="expired.password"
type="cn.pf.tbbs.exception.ServiceException"
path="/WEB-INF/jsp/comm/ServiceException.jsp">
</exception>
<exception key="expired.password"
type="java.lang.Exception"
path="/WEB-INF/jsp/comm/UnknownException.jsp">
</exception>
</global-exceptions>-->
<action-mappings>
<action path="/home"
type="cn.pf.tbbs.actions.HomeAction"
input="/index.jsp">
<forward name="home" path="/WEB-INF/jsp/home.jsp"/>
</action>
<action path="/user/User"
type="cn.pf.tbbs.actions.UserAction"
parameter="m"
input="/WEB-INF/jsp/home.jsp">
<forward name="regist" path="/WEB-INF/jsp/user/Regist.jsp"/>
<forward name="info" path="/WEB-INF/jsp/user/Info.jsp"/>
<forward name="logon" path="/WEB-INF/jsp/user/Logon.jsp"/>
</action>
<action path="/article/Article" type="cn.pf.tbbs.actions.ArticleAction"
parameter="m">
<forward name="showlist" path="/WEB-INF/jsp/article/topiclist.jsp"/>
<forward name="showpost" path="/WEB-INF/jsp/article/showpost.jsp"/>
<forward name="articleForm" path="/WEB-INF/jsp/article/ArticleForm.jsp"/>
</action>
</action-mappings>
<message-resources parameter="MessageResources"/>
</struts-config>
l
InitServlet
该类是一个初始化的
Servlet
,它负责把业务层和数据层的实现类存放到
ServletContext
容器环境中去,以便
WEB
层的调用。在写该类之前需要在
web.xml
文件中注册,并把业务层和数据层的实现类存放到该
servlet
的初始化参数中,以便告诉
servlet
我们的
userdao
是什么样的实现类。这样做还有一个好处就是参数只对该
servlet
可见。
InitServlet
的代码如下:
public class InitServlet implements Servlet {
private ServletConfig config;
public void destroy() {
System.out.println("InitServlet destroy...");
}
public ServletConfig getServletConfig() {
return this.config;
}
public String getServletInfo() {
return"init servlet";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
try {
Object userDao = Class.forName(
config.getInitParameter("userDaoClassName")).newInstance();
Class userServiceClass = Class.forName(config
.getInitParameter("userServiceClassName"));
Constructor con = userServiceClass
.getConstructor(new Class[] { UserDao.class });
Object userService = con.newInstance(new Object[] { userDao });
config.getServletContext().setAttribute(
UserService.class.getName(), userService);
Object articleDao = Class.forName(
config.getInitParameter("articleDaoClassName"))
.newInstance();
Class articleServiceClass = Class.forName(config
.getInitParameter("articleServiceClassName"));
Constructor con1 = articleServiceClass
.getConstructor(new Class[] { Article.class });
Object articleService = con1
.newInstance(new Object[] { articleDao });
config.getServletContext().setAttribute(
ArticleService.class.getName(), articleService);
} catch (Exception e) {
throw new ServletException(e.getMessage(), e);
}
}
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
注意:
(1) Web.xml中的<welcome-file>中的文件不能是映射的虚拟文件,如*.do形式的文件,否则找不到。
(2)最好把jsp页面放在应用程序的WEB-INF目录下以防外人恶意的链接。
(3)Jsp文件中如果需使用大量的taglib标签库,那么往往是用一个专门的jsp文件来引入这些taglib标签库,然后其他的jsp文件使用时就只需使用include指令引入便可。例如:
如果a.jsp中专门引入taglib标签库,那么b.jsp在使用这些标签库时只需加入指令<%@ include file=”/a.jsp”>便可。
用户模块:(
Info.jsp
,
Logon.jsp
,
Register.jsp
)
Info.jsp
是用来显示用户登录的信息,
Logon.jsp
是一个登录页面,
Register.jsp
是用来让用户填写注册信息的页面。前两者比较简单代码略,我们也可以根据自己的想法去设计。
Register.jsp
代码如下:
<%@ include file="/WEB-INF/jsp/comm/Header.jsp" %>
<form action="/sample/user/User.do" method="post" οnsubmit="return checkForm(this)">
<input type="hidden" name="a" value="exe">
<input type="hidden" name="m" value="regist">
logon name: <input type="text" name="logonName"><br>
nick name: <input type="text" name="nickName"><br>
password: <input type="password" name="password"><br>
re password: <input type="password" name="password1"><br>
<input type="submit"> <input type="reset">
</from>
发贴模块:(
ArticleForm.jsp
,
show.jsp
)
ArticleForm.jsp
是一个用来发表帖子的表单页面,代码略。
Show.jsp
用来显示帖子详细信息的页面。代码如下:
<%@ include file="/WEB-INF/jsp/comm/Header.jsp" %>
subject:<br>
title:${art.title}<br>
content:${art.content}<br>
issue:<fmt:formatDate value="${art.issue}" pattern="yyyy-MM-dd HH:mm:ss"/>
<c:if test="${session_user.id == art.author.id}">
<a href="/sample/article/Article.do?m=edit&artId=${art.id}">edit</a>
</c:if><br>
author:<a href="/sample/user/User.do?m=showUserInfo&id=${art.author.id}" target="_blank">${art.author.nickName}</a> <br>
<hr>
comment:<br>
<c:forEach var="art" items="${children}">
title:${art.title}<br>
content:${art.content}<br>
issue:<fmt:formatDate value="${art.issue}" pattern="yyyy-MM-dd HH:mm:ss"/>
<c:if test="${session_user.id == art.author.id}">
<a href="/sample/article/Article.do?m=edit">edit</a>
</c:if><br>
author:<a href="/sample/user/User.do?m=showUserInfo&id=${art.author.id}" target="_blank">${art.author.nickName}</a> <br>
</c:forEach>
<hr>
comment:<br>
<form action="/sample/article/Article.do" method="post" οnsubmit="return checkForm(this)">
<input type="hidden" name="a" value="exe">
<input type="hidden" name="parentId" value="${art.id}">
<input type="hidden" name="m" value="add">
title: <input type="text" name="title"><br>
content: <input type="text" name="content"><br>
<input type="submit"> <input type="reset">
</from>
l
构造控制层
(
1
)
UserAction
该类是一个动态的
Action
(继承
DispatchAction
),通过调用业务逻辑层接口实现用户的注册、登录、查询等功能。
代码如下:
package com.sample.web.actions;
public class UserAction extends DispatchAction {
public ActionForward regist(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String a = request.getParameter("a");
if ("exe".equals(a)) {//
判断是否已经填好信息
String logonName = request.getParameter("logonName");
String nickName = request.getParameter("nickName");
String password = request.getParameter("password");
User user = new User();
user.setLogonName(logonName);
user.setNickName(nickName);
user.setPassword(password);
//
注册
this.getUserService().regist(user);
//
使用
response.sendRedirect
()而不是用
findForward
来防止重复提交信息
response.sendRedirect("/sample/user/User.do?m=showUserInfo&id="
+ user.getId());
return null;
} else
return mapping.findForward("regist");
}
//
显示用户信息
public ActionForward showUserInfo(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)
throws Exception {
String id = request.getParameter("id");
User user = this.getUserService().getUserById(Integer.parseInt(id));
request.setAttribute("user", user);
return mapping.findForward("info");
}
public ActionForward logon(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String a = request.getParameter("a");
if ("exe".equals(a)) {
String logonName = request.getParameter("logonName");
String password = request.getParameter("password");
User user = this.getUserService().logon(logonName, password);
//
把登录用户存到
session
中
request.getSession().setAttribute("session_user", user);
response.sendRedirect("/sample/Home.do");
return null;
}
return mapping.findForward("logon");
}
public ActionForward logout(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
request.getSession().invalidate();
response.sendRedirect("/sample/Home.do");
return null;
}
private UserService getUserService() {
return (UserService) this.servlet.getServletContext().getAttribute(
UserService.class.getName());
}
}
(
3
)
ArticleAction
该类也是一个动态的
Action
(继承
DispatchAction
),通过调用
ArticleService
的方法来实现发贴,编辑,删除和显示。
程序代码如下:
package com.sample.web.actions;
public class ArticleAction extends DispatchAction {
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
this.isLogon(request);
String a = request.getParameter("a");
if ("exe".equals(a)) { //
判断用户是否是提交表单
Article art = new Article();
art.setTitle(request.getParameter("title"));
art.setContent(request.getParameter("content"));
art.setIssue(new Date());
art.setParentId(Integer.parseInt(request.getParameter("parentId")));
art.setAuthor(this.getLogonUser(request));
this.getArticleService().addArticle(art);
int artId = art.getId();
if (art.getParentId() > 0) //
判断是否重贴
artId = art.getParentId();
response.sendRedirect("/sample/article/Article.do?m=show&artId="
+ artId);
return null;
}
request.setAttribute("operater", "add");
return mapping.findForward("articleForm");
}
public ActionForward edit(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
this.isLogon(request);
String a = request.getParameter("a");
System.out.println("a:" + a);
if ("exe".equals(a)) {
//
获得要编辑的文章
Article art = (Article) request.getSession().getAttribute(
Article.class.getName());
request.getSession().removeAttribute(Article.class.getName());
art.setTitle(request.getParameter("title"));
art.setContent(request.getParameter("content"));
//
更新文章
this.getArticleService().updateArticle(art,
this.getLogonUser(request));
int id = art.getId();
if (art.getParentId() > 0)
id = art.getParentId();
System.out.println("id:" + id);
response.sendRedirect("/sample/article/Article.do?m=show&artId="
+ id);
return null;
}
int artId = Integer.parseInt(request.getParameter("artId"));
Article art = this.getArticleService().getArticleById(artId);
request.getSession().setAttribute(Article.class.getName(), art);
request.setAttribute("operater", "edit");
request.setAttribute("art", art);
return mapping.findForward("articleForm");
}
public ActionForward del(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
this.isLogon(request);
int artId = Integer.parseInt(request.getParameter("artId"));
this.getArticleService().delArticle(artId, this.getLogonUser(request));
response.sendRedirect("/sample/Home.do");
return null;
}
public ActionForward show(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
int artId = Integer.parseInt(request.getParameter("artId"));
Article art = this.getArticleService().getArticleById(artId);
List<Article> children = this.getArticleService().getChildrenArticles(
artId);
request.setAttribute("art", art);
request.setAttribute("children", children);
return mapping.findForward("show");
}
private void isLogon(HttpServletRequest request) {
User user = this.getLogonUser(request);
if (user == null)
throw new RuntimeException("no logon");
}
private User getLogonUser(HttpServletRequest request) {
return (User) request.getSession().getAttribute("session_user");
}
private ArticleService getArticleService() {
return (ArticleService) this.servlet.getServletContext().getAttribute(
ArticleService.class.getName());
}
}