zoukankan      html  css  js  c++  java
  • 从零打造在线网盘系统之Struts2框架核心功能全解析

    欢迎浏览Java工程师SSH教程从零打造在线网盘系统系列教程,本系列教程将会使用SSH(Struts2+Spring+Hibernate)打造一个在线网盘系统,本系列教程是从零开始,所以会详细以及着重地阐述SSH三个框架的基础知识,第四部分将会进入项目实战,如果您已经对SSH框架有所掌握,那么可以直接浏览第四章,源码均提供在GitHub/ssh-network-hard-disk上供大家参阅

    我相信你在使用任何一个MVC框架的时候都会接触到以下功能,你必须要会使用这些功能才能够在Struts2中熟练的解决大多数问题

    本篇目标

    • 接收参数
    • 参数校验
    • 数据转换
    • 响应数据
    • 上传下载
    • 异常处理
    • 国际化支持

    接收参数 示例源码下载

    Struts2接收参数有三种方式,

    1. Servlet API
    2. getter和Setter方法
    3. 模型驱动

    Servlet API

        @Action(value = "register")
        public void register() {
            ActionContext context = ActionContext.getContext();
            HttpServletRequest httpServletRequest = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
            String username = httpServletRequest.getParameter("username");
            String password = httpServletRequest.getParameter("password");
            System.out.println("username:" + username + "    password:" + password);
        }
    

    getter和Setter方法

        private String username;
        
        private String password;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Action(value = "register")
        public void register() {
            System.out.println("username:" + username + "    password:" + password);
        }
    

    当然你也可以使用JavaBean进行接收参数,类似下面这样,前端传递的name属性需要有些变动,name属性需要改成xxxx.xxx与属性名一致

    <form action="register.action" method="get">
        <input name="user.username" type="text">
        <input name="user.password" type="text">
        <input type="submit">
    </form>
    
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Action(value = "register")
        public void register() {
            System.out.println("username:" + user.getUsername() + "    password:" + user.getPassword());
        }
    

    模型驱动

    @ParentPackage("default")
    public class RegisterAction implements ModelDriven<User> {
    
    
        private User user = new User();
    
        @Override
        public User getModel() {
            return user;
        }
        
        @Action(value = "register")
        public void register() {
            System.out.println("username:" + user.getUsername() + "    password:" + user.getPassword());
        }
    
    
    }
    ![1](7623C3566DA045869126C1B9D546A934)
    

    参数校验 示例源码下载

    对于前端传递的参数来讲,存在太多不稳定性,所以对于参数的校验是必不可少的,对于校验来说大体上分为两种,一种是前端校验,一种是后端校验,前端校验的方法在这里就不再累述,这里仅仅讲述Struts2如何使用Validation校验框架

    获取参数

      private String username;
      private String password;
      getter and setter......
    

    在Action同级目录增加-validation.xml

    <!DOCTYPE validators PUBLIC
            "-//Apache Struts//XWork Validator 1.0.2//EN"
            "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
    
    <validators>
        <!-- 要对哪个属性进行验证 -->
        <field name="username">
            <!-- 验证规则 -->
            <field-validator type="requiredstring">
                <!-- 违反规则的提示 -->
                <message>用户名不能为null!</message>
            </field-validator>
        </field>
        <field name="password">
            <field-validator type="requiredstring">
                <message>密码不能为null</message>
            </field-validator>
        </field>
    
    </validators>
    

    核心Action(这里可以看到如果校验正确跳转 "/success.jsp",如果校验失败错误信息输出在"/form.jsp")

        @Override
        @Action(value = "register", results = {
                @Result(name = SUCCESS, location = "/success.jsp"),
                @Result(name = INPUT,location = "/form.jsp")
        })
        public String execute() throws Exception {
            System.out.println("username"+username+"password:"+password);
            return SUCCESS;
        }
    
    

    下载本小节源码访问http://localhost:8080/form.jsp

    数据转换 示例源码下载

    WEB系统都是基于网页形式的,接收到的信息都是字符串,Java又是强类型的语言,所以必须需要一个转换的过程.而Struts2的类型转换是基于OGNL表达式的,只需要将表单中的name属性根据OGNL规则命名就能转换成相应的Java类型,通常情况下哦我们无需建立自己的类型转换器,Struts2的内建转换器完全能帮助我们完成任务

    例如我们有下面一个需求(包含Integer,Date,数组的转换)

    我们该怎么办呢?不不不~~~~我们什么都不用做正常编写Action就行了,Struts2会自动帮我们进行转换

    public class RegisterAction extends ActionSupport implements ModelDriven<User> {
    
        private User user = new User();
    
        @Override
        public User getModel() {
            return user;
        }
        @Override
        @Action(value = "register", results = {
                @Result(name = SUCCESS, location = "/success.jsp")
        })
        public String execute() throws Exception {
            System.out.println(user.toString());
            return SUCCESS;
        }
    }
    
    

    好吧,真的没什么挑战力,下面我们要自己实现转换器了

    例如:我们需要将字符串"自行车,1033,100"转换为Java的Product对象

    自定义转换器

    public class StringToProductTypeConverter extends DefaultTypeConverter {
        
        @Override
        public Object convertValue(Map context, Object value, Class toType) {
            if (toType == Product.class) {
                String[] params = (String[]) value;
                Product product = new Product();
                String[] productValues = params[0].split(",");
                product.setProductName(productValues[0].trim());
                product.setPrice(Float.parseFloat(productValues[1].trim()));
                product.setCount(Integer.parseInt(productValues[2].trim()));
                return product;
            } else if (toType == String.class) {
                Product product = (Product) value;
                return product.toString();
            }
            return null;
        }
    
    }
    

    配置全局转换器(在WEB-INFclasses目录新建xwork-conversion.properties)

    com.jimisun.action.Product=com.jimisun.action.StringToProductTypeConverter
    

    在Action中接收(不要使用模型驱动方式接收参数,接收不到)

    public class ProductAction extends ActionSupport {
    
        private Product product;
    
        public Product getProduct() {
            return product;
        }
    
        public void setProduct(Product product) {
            this.product = product;
        }
    
        @Override
        @Action(value = "register", results = {
                @Result(name = SUCCESS, location = "/success.jsp")
        })
        public String execute() throws Exception {
            System.out.println(product.toString());
            return SUCCESS;
        }
    }
    

    响应数据 示例源码下载

    我们一直都没有探讨一个问题,那就是Struts2的结果的响应.对于任何一个程序而言,最重要的莫过于输入和输出,当我们了解了Struts2接收参数后,现在我们一起来看一看Struts2如何响应参数吧

    • Servlet API存取值
    • 属性值存取值
    • 值栈Set方法存取值
    • 值栈Push方法存取值

    Servlet API存取值

        ActionContext context = ActionContext.getContext();
        HttpServletRequest request  = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
        request.setAttribute("requestValue","requestValue");
    
    <%--从Servlet API的Request域对象中取值--%>
    Request取值:<s:property value="#request.requestValue"/>
    

    属性值存取值

    private User user = new User("jimisun", "jimisun");
    
    <%--获取属性值--%>
    简单属性取值:<s:property value="user.username"/>
    

    那么对于复杂的属性存取值我们可以这样,例如List

    private List<User> list = new ArrayList<>();
      User user1 = new User("list1","list1");
      User user2 = new User("list2","list2");
      list.add(user1);
      list.add(user2);
    
    <%--获取属性List值--%>
    list属性取值:
    <br>
    <s:iterator value="list" var="user">
    
        <s:property value="#user.username"/>
        <s:property value="#user.password"/>
        <br/>
    </s:iterator>
    

    值栈Set方法存取值

     ActionContext context = ActionContext.getContext();
     ValueStack valueStack = context.getValueStack();
     valueStack.set("valueStackDemo", "valueStackDemoSet");
    
    <%--值栈Set方法取值--%>
    值栈set取值:<s:property value="valueStackDemo"/>
    

    值栈Push方法存取值

     ActionContext context = ActionContext.getContext();
     ValueStack valueStack = context.getValueStack();
     valueStack.push("valueStackPush");
    
    <%--值栈Push方法取值--%>
    值栈push取值:<s:property value="[0].top"/>
    

    OK,现在对于Struts2的几种数据的响应方式我们大概已经知道了,现在我们来看一看这几种存储数据方式在值栈中的结构,在本小节源码中运行项目直接访问http://localhost:8080/outputdate.action即可

    注意点:使用OGNL表达式访问"根"对象中的对象及属性时,不需要前面加"#"号

    文件上传 示例源码下载

    对于文件上传功能Struts2并没有提出自己的解决方案,但是Struts2为文件上传提供了统一的接口,开发人员在使用上传文件的组件时,并不需要知道太多的细节就可以轻松使用他们,Struts2目前支持三种上传文件组件Commons-FileUpload,cos,pell,例如我们使用Commons-FileUpload为例来快速学习文件上传功能

    commons-fileupload依赖(已经内置,无须再次添加)

    struts.properties相关配置

    struts.multipart.parser=jakarta
    struts.multipart.maxSize=2097152
    

    核心上传代码

        @Action(value = "UploadAction", params = {"uploadPath", "D:/"}, results = {
                @Result(name = "success", location = "/result.jsp")
        })
        public String execute() throws Exception {
            String fn = "";
            if (filename.equals("")) {
                fn = uploadPath + uploadFileName;
            } else {
                fn = uploadPath + filename;
            }
    
            if (new File(fn).exists()) {
                result = "该文件已经存在!";
            } else {
                FileOutputStream fileOutputStream = new FileOutputStream(fn);
                InputStream inputStream = new FileInputStream(upload);
                byte[] buffer = new byte[8192];
                int count = 0;
                while ((count = inputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, count);
                }
                fileOutputStream.close();
                inputStream.close();
                result = "文件上传成功!";
            }
            return "success";
        }
    

    下面我们再进行展示同时上传多个文件的示例,对于同时上传多个文件,我们仅仅需要做一点改变即可,即接收值的属性改成数组或者List集合

        private File[] upload;
        private String[] uploadFileName;
    
        @Action(value = "UploadAction", params = {"uploadPath", "D:/"}, results = {
                @Result(name = "success", location = "/result.jsp")
        })
        public String execute() throws Exception {
            for (int i = 0; i < uploadFileName.length; i++) {
                String fn = uploadPath + uploadFileName[i];
                FileOutputStream fileOutputStream = new FileOutputStream(fn);
                InputStream inputStream = new FileInputStream(upload[i]);
                byte[] buffer = new byte[8192];
                int count = 0;
                while ((count = inputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, count);
                }
                fileOutputStream.close();
                inputStream.close();
            }
            result = "文件上传成功!";
            return "success";
        }
    

    我们了解了文件上传那么现在我们再来一起看一下文件的下载,再Struts2中提供了一种使用Stream下载文件的方式,类似于文件和浏览器的一个"代理",通过这个"代理"我们就能控制某某下载文件,如下是一个Download的Action

    public InputStream getFileInputStream() {
            // 以及文件的mime类型以及创建流
            ServletContext context = ServletActionContext.getServletContext();
            contentType = context.getMimeType(context.getRealPath(filePath + "/" + fileName));
            setContentType(contentType);
            return context.getResourceAsStream(filePath + "/" + fileName);
        }
    
        @Override
        @Action(value = "download", params = {"filePath", "/file"}, results = {
                @Result(name = SUCCESS, type = "stream",
                        params = {"contentType", "${contentType}", "inputName", "fileInputStream", "contentDisposition", "attachment;filename="${fileName}""})
        })
        public String execute() throws Exception {
            return SUCCESS;
        }
    

    异常处理 示例源码下载

    异常处理是任何成熟的MVC框架必备的功能,在Struts2中提供了异常的拦截器,我们可以在struts.xml文件中进行配置异常,以灵活的方式处理异常

    配置全局异常

        <package name="default" extends="struts-default" namespace="/">
            <global-results>
                <result name="exception">/error.jsp</result>
            </global-results>
            
            <global-exception-mappings>
                <exception-mapping exception="java.sql.SQLException" result="exception"></exception-mapping>
            </global-exception-mappings>
            
            ...
        </package>
    

    模拟异常

    @ParentPackage("default")
    public class ExceptionAction extends ActionSupport {
    
    
        @Override
        @Action(value = "testerror", results = {
                @Result(name = SUCCESS, location = "/success.jsp")
        })
        public String execute() throws Exception {
            if ("a".equals("a")) {
                throw new SQLException("SQL错误!!!");
            }
            return SUCCESS;
        }
    }
    

    当发生异常后就会跳转到所配置的error.jsp页面

    国际化支持 示例源码下载

    Struts2的国际化支持是建立在Java对国际化的支持之上的,对Java的国际化支持进行了封装,下面我们来针对一段优美的诗,我们我们将会展示中文和英文两种页面给访问者

    我那美丽的女孩 我的挚爱 无论梦里梦外 去去来来

    抬头眺望云端 高不可攀 低头忆你容颜 温柔绚烂

    配置Struts2全局资源文件(使用下面两种方式都可以)

    在struts.properties中配置
    struts.custom.i18n.resources=Resource
    
    在struts.xml中配置
    <constant name="struts.custom.i18n.resources" value="Resource"/>
    

    创建两个资源文件(中文和英文)

    Resource_en_US.properties

    welcome = hello,{0}
    content = My beautiful girl, my love, my dream, my dream, my dream, my dream, my dream
    

    Resource_zh_CN.properties

    welcome = 你好,{0}
    content = 我那美丽的女孩 我的挚爱 无论梦里梦外 去去来来 抬头眺望云端 高不可攀 低头忆你容颜 温柔绚烂
    

    在Action中使用

    public class BeautifulGirlAction extends ActionSupport {
    
        private String username;
        private String content;
        private String welcome;
    
        @Override
        @Action(value = "girl", results = {
                @Result(name = SUCCESS, location = "/success.jsp")
        })
        public String execute() throws Exception {
            welcome = getText("welcome", new String[]{username});
            content = getText("content");
            return SUCCESS;
        }
        ...
    }
    

    通过下载本小节示例源码访问http://localhost:8080/form.jsp

    本章总结

    在WEB应用中常见的功能是很多的,很多场景下Struts2都为我们提供了响应的解决方案,本章叙述中在下主要讲述了Struts2的常见的功能的基本使用,即只有广度而没有深度,更为深度的学习还希望小伙伴们查阅相关资料,例如OGNL表达式等...

  • 相关阅读:
    互联网秒杀设计
    生产者消费者模式实现
    Ping CAP CTO、Codis作者谈redis分布式解决方案和分布式KV存储
    VIM使用学习笔记 : 按键说明
    Cookie的有效访问路径
    简单的Cookie记录浏览记录案例
    认识Cookie和状态管理
    Java异常
    Java接口基础
    String常用方法
  • 原文地址:https://www.cnblogs.com/jimisun/p/9969406.html
Copyright © 2011-2022 走看看