J2EE struts2MVC应用在线书签1

序:之前花了一天研究了一下filter,虽然是实现了MVC模式开发了 WebBookmark,但是代码过于冗长,集中在filter中使用if语句不易阅读,为了体现两份作业的不同点,我决定学习 JavaEE下的struts2框架,实现WebBookmark的MVC模式,这一次,代码将会更加清晰,代码文件分布也会更加容易被读懂,这一次敏捷学习,将会沿用上一代产品的部分代码技术,同时也会暴露很多愚蠢的使用方式,毕竟不是专业的JavaEE程序员,见谅。

科普:struts2与struts从框架构成来说,完全是两个不同产品,可能大部分新手会觉得这两个东西名儿都一样,struts2一定是struts的 升级版吧,不然,我们不要慵懒的认为struts1书写的项目可以轻松升级到struts2,这么说,要升级几乎就要重写。因为struts2根本不是 struts1升级来这么简单的,struts2基于WebWork2,是完全不同于struts1的框架,Struts2对应的有自己的标签,并且功能 强大。Webwork也有自己的标签。在2005年12月,WebWork与Struts Ti决定合并, 在此同时, Struts Ti 改名为 Struts Action Framework 2.0,成为Struts真正的下一代。官方这么做纯粹是为了炒作,因为struts1很火,但事实上很糟糕,需要被更加优秀的WebWork淘汰掉了, 于是为了拯救这个商标,他们直接升级了Webwork,命名为struts2,基于大名鼎鼎的struts使得struts2可以不费吹灰之力,一炮走 红!

技术点一:搭建struts框架环境

接下来我们看看struts2的搭建,还是基于javaweb的dynamic web project应用,创建详情请看我的博客《带你在javaee世界起飞——开发环境搭建》!

我们直接上struts2环境搭建(注意:基于javaee环境已经搭建好了),struts2将会把应用的代码质量带上一个新的高度,首先下载几个jar包作为类库:

第一步:下载并解压struts2:

       1.百度“struts2”即可,上“http://struts.apache.org/”下载struts-2.3.24.1-all.zip包

       2.打开压缩文件=》apps/struts2-blank.war这个应用

              解压其中的/WEB-INF/lib下的jar包,安放到新建的WebBookmark对应的/WebContent/WEB-INF/lib下

              解压/src/java/struts.xml到新建项目的java source/src下

第二步:修改web.xml文件(注意在新建项目最后一个next窗口finish前需要勾选)

 

 

xml文件在WebContent/WEB-INF/下,配置如下:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

  <display-name>WebBookmark</display-name>

 

<filter>

<filter-name>struts2</filter-name>

<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

<init-param>    

      <param-name>encoding</param-name>    

      <param-value>utf8</param-value>    

</init-param>

</filter>

 

<filter-mapping>

<filter-name>struts2</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

</web-app>

 

其实这段代码可以直接在刚刚解压的struts2-blank这个项目相同位置找到并复制!

我们看看这个xml文件主要就配置了两项,一个是filter,另一个是filter-mapping,咦,不就是我们用的filter过滤器吗?这么配置只不过是把servlet的过滤器交给的struts2框架

另外welcome-file设置项目首页为index.jsp。

第三步,设置struts.xml:

既 然使用了struts作为filter,那么我们不用在像第一次开发那样自己去制作filter了,统统交给struts2配置,那么所有的配置,最麻烦 的地方是我们要不停往这个struts2.xml文件添加配置项了,且先看完整的WebBookmark项目所需的配置文件吧,上代码:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="true"/>

    <constant name="struts.configuration.xml.reload" value="true"/>

    <constant name="struts.i18n.encoding" value="UTF-8"/>

    <!--配置Convention 插件自动重加载映射 -->

    <constant name="struts.convention.classes.reload" value="true"/>

    <!--user-->

    <package name="BookmarkUser" namespace="/user" extends="struts-default">

        <!--列出bookmark-->

        <action name="list" class="cslg.cn.controller.BookmarkAction" method="list">

            <result name="list">/WEB-INF/view/user/list.jsp</result>

            <result name="error" type="">/index.jsp</result>

        </action>

        <!--新增bookmark-->

        <action name="add" class="cslg.cn.controller.BookmarkAction" method="add">

            <result name="add">/WEB-INF/view/user/add.jsp</result>

            <result name="error" type="">/index.jsp</result>

        </action>

        <!--保存-->

        <action name="save" class="cslg.cn.controller.BookmarkAction" method="save">

            <result name="success" type="redirect">/user/list.action</result>

            <result name="error">/WEB-INF/view/user/error.jsp</result>

            <result name="login" type="">/index.jsp</result>

        </action>

        <!--删除-->

        <action name="del" class="cslg.cn.controller.BookmarkAction" method="del">

            <result name="success" type="redirect">/user/list.action</result>

            <result name="error">/WEB-INF/view/user/error.jsp</result>

            <result name="login" type="">/index.jsp</result>

        </action>

        <!--登录操作-->

        <action name="login" class="cslg.cn.controller.UserAction" method="login">

            <!--登录成功:重置到list页面-->

            <result name="success" type="redirect">/user/list.action</result>

            <!--登录错误:首页(非重置)-->

            <result name="error" type="">/index.jsp</result>

        </action>

        <!--注销操作-->

        <action name="logout" class="cslg.cn.controller.UserAction" method="logout">

            <result name="logout" type="">/index.jsp</result>

        </action>

    </package>

    <!--admin操作-->

    <package name="BookmarkAdmin" namespace="/admin" extends="struts-default">

        <!--登录操作-->

        <action name="login" class="cslg.cn.controller.UserAction" method="login">

            <!--登录成功:重置到list页面-->

            <result name="success" type="redirect">/admin/list.action</result>

            <!--登录错误:首页(非重置)-->

            <result name="error" type="">/index.jsp</result>

        </action>

        <!--列出user-->

        <action name="list" class="cslg.cn.controller.UserAction" method="list">

            <result name="list">/WEB-INF/view/admin/list.jsp</result>

            <result name="error" type="redirect">/index.jsp</result>

        </action>

        <!--新增user-->

        <action name="add" class="cslg.cn.controller.UserAction" method="add">

            <result name="add">/WEB-INF/view/admin/add.jsp</result>

            <result name="error" type="">/index.jsp</result>

        </action>

        <!--保存-->

        <action name="save" class="cslg.cn.controller.UserAction" method="save">

            <result name="success" type="redirect">/admin/list.action</result>

            <result name="error">/WEB-INF/view/adminr/error.jsp</result>

            <result name="login" type="">/index.jsp</result>

        </action>

        <!--删除-->

        <action name="del" class="cslg.cn.controller.UserAction" method="del">

            <result name="success" type="redirect">/admin/list.action</result>

            <result name="error">/WEB-INF/view/admin/error.jsp</result>

            <result name="login" type="">/index.jsp</result>

        </action>

        <!--注销操作-->

        <action name="logout" class="cslg.cn.controller.UserAction" method="logout">

            <result name="logout" type="">/index.jsp</result>

        </action>

    </package>

</struts>

 

xml文件有点小复杂,但是稍作介绍,就能明白原理。

首先,所有的配置都写在struts这个大架子里面。开头是一些开发中用的初始化,不必多了解,为了方便开发的调试,统一文字编码而已。

然后,我们看到两个<package>,一个注释为user,意为普通用户的功能,另一个是admin,意为超级用户的功能,在 struts.xml下,package可以作为命名空间,相当于把他们安放在了不同的路径目录“/user”和“/admin”中,注意既然这么设置 了,那么访问的时候,所有关于普通用户操作bookmark的功能url都是“/WebBookmark/user/xxx.action”,同理admin用户管理用户的功能url都在“/WebBookmark/admin/xxx.action”。这个在前端开发中尤为重要,而且不同package的namespace中跳转的相对路径都在当前命名空间下,因为每个命名空间都被看成为一个目录,所以相对路径理所当然是当前空间目录下。

再后,看<action>,这个是调用java source下的功能的核心,一个action对应一个访问的方法,class映射到java source下package下的类,method映射到类下的方法名,那么name属性就是为用户提供的访问方法,就是url中 “xxx.action”的xxx啦!

最后,请看<result>,意为“结果”,就是执行完后的页面跳转,里面夹着一个页面,这个页面也可以是另外一个url访问,也可以是对应服务器的jsp文件的物理路径,有一个name是什么呢?一会儿解释!

 

至少我们已经配置完成了所有的struts配置,也已经把前(V)后(C,M)端分离了,MVC已经基本实现,来看看新目录结构:

1.java文件

 

 

2.前端文件

 

 

3.类库文件,其中mysql连接和jstl请参照《J2EE MVC应用在线书签——filter实现1》一文,并没有变

 

 

主要是多了struts的类库罢了

 

技术点二:struts2控制器下的action的getter,setter方法

在这儿,我发现struts2有个特别的功能,可以将controller和model结合使用,但我没有做深入研究,这里提一下,请看下面这段代码:

public class UserAction {

        /*

         * Model:User

         */

        private Integer id;

        private String username;

        private String password;

        private String user;

 

        public String getUser() {

                return user;

        }

 

        public void setUser(String user) {

                this.user = user;

        }

 

/*其他getter,setter方法略*/

 

     public String login() {

                // 普通用户

                if ("user".equals(this.getUser())) {

                        String sql = "select * from user where username='" + this.getUsername() + "' and password='"

                                        + this.getPassword() + "'";

                        MyDB db = new MyDB();

                        try {

                                db.openConnection();

                                ResultSet res = db.executeQuery(sql);

 

上面这段代码来自“UserAction.java”,被精简了,但是总结下来无非两个东西,一个是user类的 getter方法,一个是setter方法,我们在filter中,把这个类分离在了Model(模型)中了,但在这里我们直接放在action中,并且 发挥了作用,原来struts2可以把form表单提交的数据(无论post,get方式)利用actiong下的setter方法存储到私有变量中,然 后使用this.getXxx()方法直接在Action之后的方法中获得,这是及其方便的,但,我只用了一次,后面的方法中,我们使用另一种接收方法获取。

 

技术点三,借用servlet来获取form表单提交的数据

看下面这行代码:

String url = "http://"+ new String(ServletActionContext.getRequest().getParameter("url")).trim();

 

来自“BookmarkAction.java”,这样获取表单数据看上去很愚蠢,但是借用servlet的方法也是很机智的绕过了很多struts特性,对于敏捷学习的初学者来说相当的实用。

 

技术点四,借用servlet来操作session

看下面两段代码:

保存session:

ActionContext.getContext().getSession().put("loginuser", loginuser);

 

获取已有session:

User user = (User) ActionContext.getContext().getSession().get("loginuser");

 

也是借用了servlet的session

 

技术点五,借用servlet向jsp发送标签

后端代码:

ServletActionContext.getRequest().setAttribute("message", "错误:该用户已存在!");

 

前端代码:

${requestScope.message }

 

后端代码:

                      

  List<BookMark> bms = new ArrayList<BookMark>();

                        MyDB db = new MyDB();

                        String sql = "select * from bookmark where userid = '" + user.getId() + "';";

                        try {

                                db.openConnection();

                                ResultSet res = db.executeQuery(sql);

                                while (res.next()) {

                                        BookMark bm = new BookMark(res.getInt(1), res.getString(2), res.getString(3), res.getString(4),

                                                        res.getInt(5));

                                        bms.add(bm);

                                }

                                db.closeConnection();

                        } catch (SQLException e) {

                                e.printStackTrace();

                        }

                        ServletActionContext.getRequest().setAttribute("list", bms);

 

前端代码,由于后端set一个对象列表,前端使用JSTL标签foreach出来:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<c:forEach items="${list}"  var="list"  varStatus="num">

    <tr>

        <td>${list.sitename}</td>

        <td>${list.url}</td>

        <td>${list.cate}</td>

        <td><a href="add.action?id=${list.id}">修改</a>&nbsp;<a

                href="del.action?id=${list.id}">删除</a></td>

    </tr>

</c:forEach>

 

技术点六,方法的返回处理字符串

注意,在struts.xml对应的所有Action类下的method,即方法,最后返回值都是String类型,所以所有方法都是“public String xxx(){}”形式的;

且看下面的代码,是删除一条书签的方法:

public String del() throws UnsupportedEncodingException {

    User user = (User) ActionContext.getContext().getSession().get("loginuser");

 

    //检查session

    if (user != null && user.getId() > 0) {

        // 获取id

        String getid = new String(ServletActionContext.getRequest().getParameter("id").getBytes("ISO-8859-1"),

                "UTF-8").trim();

        Integer id = Integer.parseInt(getid);

        MyDB db = new MyDB();

        String sql = "delete from bookmark where id='" + id + "'";

        if (id > 0 && id != null) {

            try {

                db.openConnection();

                db.executeUpdate(sql);

                db.closeConnection();

                return "success";

            } catch (SQLException e) {

                e.printStackTrace();

            }

        }

        return "error";

    }

 

    return "login";

}

 

有三种情况,返回success,返回error,返回login,分别对应删除成功,删除失败,未登录返回登录,然后看关于它的struts.xml配置:

<action name="del" class="cslg.cn.controller.UserAction" method="del">

    <result name="success" type="redirect">/admin/list.action</result>

    <result name="error">/WEB-INF/view/admin/error.jsp</result>

    <result name="login" type="">/index.jsp</result>

</action>

 

很明显,最终返回的字符串是被映射到了struts的result标签的name属性上,例如返回了success,最终以type="redirect"的形式跳转到list.action,重新列出所有的书签,另外两个显而易见,分别跳转到错误页,登录页(index.jsp被设定为登录页)!

 

技术点七,公用edit和add页面

从代码高可用性的角度说,edit和add页面其实是可以公用的,且看前端代码:

<form action="save.action" method="post" class="am-form am-form-horizontal">

    <input type="hidden" name="id" value="${requestScope.bookmark.id}" />

    <div class="am-form-group">

        <label for="url" class="am-u-sm-2 am-form-label">网 址:http://</label>

        <div class="am-u-sm-10">

            <input type="text" id="url" name="url" placeholder="输入书签地址"

                value="${requestScope.bookmark.url}">

            </div>

        </div>

        <div class="am-form-group">

            <label for="sitename" class="am-u-sm-2 am-form-label">网站名称:</label>

            <div class="am-u-sm-10">

                <input type="text" id="sitename" name="sitename" placeholder="输入网站名称"

                    value="${requestScope.bookmark.sitename}">

                </div>

            </div>

            <div class="am-form-group">

                <label for="cate" class="am-u-sm-2 am-form-label">分类:</label>

                <div class="am-u-sm-5">

                    <select name="cate" id="cate">

                        <option value="">选择分类</option>

                        <c:forEach items="${list}" var="list" varStatus="num">

                            <option value="${list.catename}"

                                <c:if test="${requestScope.bookmark.cate==list.catename}">selected</c:if>>${list.catename }</option>

                        </c:forEach>

                    </select>

                </div>

                <div class="am-u-sm-5">

                    <input type="text" name="newcate" placeholder="新增一个分类"/>

                </div>

            </div>

            <div class="am-form-group">

                <div class="am-u-sm-10 am-u-sm-offset-2">

                    <button type="submit" class="am-btn am-btn-primary am-btn-block">提交</button>

                </div>

            </div>

        </form>

 

我们只需要一个hidden的input传递一个bookmark的id来标记,id存在即为编辑模式,不存在即为添加模式,在后端进行判断,且看代码:

//获取id

String id = Se)vletActionContext.getRequest().getParameter("id").trim();

 

String sql = "";

if (!"".equals(id)) {

    bm.setId(Integer.parseInt(id));

    sql = "update bookmark set url='" + bm.getUrl() + "', sitename='" + bm.getSitename() + "', cate='"

        + bm.getCate() + "' where userid=" + user.getId() + " and id=" + bm.getId() + ";";

} else {

    sql = "INSERT INTO bookmark VALUES (null,'" + bm.getUrl() + "','" + bm.getSitename() + "','"

        + bm.getCate() + "','" + bm.getUserid() + "');";

}

 

如果存在id就执行update语句,不存在就insert into。

posted @ 2017-01-17 15:24  devilyouwei  阅读(245)  评论(0编辑  收藏  举报