序:之前花了一天研究了一下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。

J2EE struts2MVC应用在线书签1的更多相关文章

  1. 超棒的响应式设计测试书签和工具(bookmarks)(转)

    一.测试书签(bookmarks) Viewport Resizer 这个书签号称拥有158个国家3万多活跃的用户,主要特性: 完全自定制 方便的添加自定义尺寸 手动的横竖屏切换 自动的横竖屏切换 ( ...

  2. 常用的Firefox浏览器插件、Chrome浏览器插件收藏

    [血的教训] 不要去下载“Firefox中国版(谋智网络)”,默认情况下会给你安装好多的莫名其妙的插件,推荐去Firefox官方下载原版. Firefox 原版官方网址: https://www.mo ...

  3. Avant Browser

    Avant Browser Avant 浏览器友好的用户界面为你的网络冲浪带来全新的效率和透明性.软件版本的不断升级使产品的可靠性稳步提高. 没有广告.没有恶意软件! Avant 浏览器是免费的.10 ...

  4. J2EE用监听器实现同一用户只能有一个在线

    这里我们讨论的是已登陆或将要登陆的用户,游客不在讨论的范围之内.这一点大家应该很容易就能理解的吧.                那么我们应该怎样去实现同一用户只能有一个在线这样的一个小功能呢? 有人 ...

  5. J2EE课程设计:在线书店管理系统

    1.系统实现 使用SpringMVC框架进行开发 使用Maven进行系统构建 使用MySql数据库 项目只实现了查看图书,搜索图书,加入购物车,创建订单,图书管理等基本功能 前台使用Bootstrap ...

  6. J2EE开发时的包命名规则

    http://www.blogjava.net/paulwong/archive/2012/04/15/374675.html 转一个J2EE开发时的包命名规则,养成良好的开发习惯 代码编写规范目的: ...

  7. Java开发常用的在线工具

    原文出处: hollischuang(@Hollis_Chuang) 作为一个Java开发人员,经常要和各种各样的工具打交道,除了我们常用的IDE工具以外,其实还有很多工具是我们在日常开发及学习过程中 ...

  8. 很不错的在线Office控件:IWebOffice与SOAOffice

    http://blog.csdn.net/cjh200102/article/details/17220441 iWebOffice2003文档控件 iWebOffice2003网络文档中间件能够在I ...

  9. 使用 CSS3 & jQuery 制作漂亮的书签动画

    今天的教程是关于创建使用 CSS 旋转变换和 JavaScript 制作动画书签效果.我们的想法是展现出样书状结构,使单一的色板或列表点击切换.当点击其中一项,我们就会旋转以显示所选择的项目. 在线演 ...

随机推荐

  1. Android四大组件详解

    注:本文主要来自网易的一个博主的文章,经过阅读,总结,故留下文章在此 Android四大基本组件介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content P ...

  2. mysql数据库开启慢查询日志

    修改配置文件 在配置文件my.ini中加上下面两句话 log-slow-queries = C:\xampp\mysql_slow_query.log long_query_time=3 第一句使用来 ...

  3. 开源免费的.NET图像即时处理的组件ImageProcessor

    承接以前的组件系列,这个组件系列旨在介绍.NET相关的组件,让大家可以在项目中有一个更好的选择,社区对于第三方插件的介绍还是比较少的,很多博文的内容主要还是介绍一些简单的操作(很多人都说博客园现在是“ ...

  4. Office 365开发概述及生态环境介绍(一)

    原文于2017年3月13日首发于LinkedIn,请参考这个链接 离上一篇文章,很快又过去了两星期的时间.今天抓紧晚上的时间,开始了Office 365开发系列文章的第一篇,我会帮助大家回顾一下过去O ...

  5. C#随机取得可用端口号

    TCP与UDP段结构中端口地址都是16比特,可以有在0---65535范围内的端口号.对于这65536个端口号有以下的使用规定: (1)端口号小于256的定义为常用端口,服务器一般都是通过常用端口号来 ...

  6. artemplate使用

    最近写了一个菜谱展示的网页,其中用到了artemplate模板,关于artemplate的好处就不多说了,直接上干货 1. <script src="js/template-nativ ...

  7. bzoj3531——树链剖分+动态开点线段树

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连 ...

  8. Shell常见用法小记

    shell的简单使用 最近发现shell脚本在平常工作中简直算一把瑞士军刀,很多场景下用shell脚本能实现常用的简单需求,而之前都没怎么学习过shell,就趁机把shell相关的语法和常见用法总结了 ...

  9. 【C语言】浅谈可变参数与printf函数

    一.何谓可变参数 int printf( const char* format, ...); 这是使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用& ...

  10. 老李回答:JAVA程序的性能测试方法

    Java 1.5以上都在虚拟机里内建了程序性能跟踪的功能,并提供了Java Profiling API,简称JPA,你可以搜索'java profiling'.Java也提供了简单的性能性能跟踪工具J ...