史上最简单的 Spring MVC 教程(九)

1 前言


在史上最简单的 Spring MVC 教程(五、六、七、八)等四篇博文中,咱们已经分别实现了“人员列表”的显示、添加、修改和删除等常见的增、删、改、查功能。接下来,也就是在本篇博文中,咱们在继续实现新的功能,即:上传图片和显示图片。

2 注解示例 - 上传及显示图片


老规矩,首先给出项目结构图:

项目结构图

2.1 显示图片


第一步:修改 web.xml 文件,拦截所有的 URL

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- 配置 Spring 框架 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:beans.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 配置 DispatcherServlet,对所有后缀为action的url进行过滤 -->
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 修改 Spring MVC 配置文件的位置和名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>/</url-pattern>  <!-- 拦截所有的 URL -->
    </servlet-mapping>

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

</web-app>

第二步:修改 springmvc-servlet.xml 文件,增加静态资源的管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd ">

    <!-- 声明注解开发方式 -->
    <mvc:annotation-driven/>

    <!-- 静态资源的管理 -->
    <mvc:resources location="/upload/" mapping="/upload/**"/>

    <!-- 包自动扫描 -->
    <context:component-scan base-package="spring.mvc.controller"/>

    <!-- 内部资源视图解析器,前缀 + 逻辑名 + 后缀 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

第三步:修改 web 目录下的 index.jsp 页面,增加跳转链接及显示图片

<%-- Created by IntelliJ IDEA. User: 维C果糖 Date: 2017/1/29 Time: 21:25 To change this template use File | Settings | File Templates. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Spring MVC</title>
</head>
<body>
This is my Spring MVC!<br>

<a href="${pageContext.request.contextPath}/person/all.action">显示人员列表</a>

<img src="${pageContext.request.contextPath}/upload/SoCuteCat.jpg">
</body>
</html>

在完成以上步骤后,启动 tomcat 服务器,默认访问 http://localhost:8080/springmvc-annotation/,页面如下所示:

默认显示页面

然后,点击“显示人员列表”,将访问 http://localhost:8080/springmvc-annotation/person/all.action,页面如下所示:

显示人员列表

额外提示:在大型网站的框架中,常见的配置是动态资源和静态资源分别解析,主要有两种选择,分别是

  • 第一种:Apache + tomcats(集群)
  • 第二种:Nginx + tomcats(集群)

其中,Apache 和 Nginx 是负责负载均衡,即平均分配资源,同时用它们来解析静态资源,例如 JavaScript、CSS 和 Image 等;tomcat 集群负责动态资源的解析,例如 jsp 和 action 等。至于为什么会衍生出用 Nginx 代替 Apache 的第二种方案,主要是因为 Nginx 的处理速度是 Apache 的 100 倍。

2.2 上传图片

第一步:修改实体类(Person),添加图片存储路径的字段

package spring.mvc.domain;

/** * Created by 维C果糖 on 2017/1/30\. */

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String photoPath;  // 图片存储路径

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPhotoPath() {
        return photoPath;
    }

    public void setPhotoPath(String photoPath) {
        this.photoPath = photoPath;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第二步:修改控制器(PersonController)中的 updatePersonList 方法

package spring.mvc.controller;

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import spring.mvc.domain.Person;
import spring.mvc.service.PersonService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/** * Created by 维C果糖 on 2017/1/26\. */

@Controller
public class PersonController {
    @Resource
    PersonService ps;    // 注入 service 层

    @RequestMapping(value = "/person/all")
    public String findAll(Map<String, Object> model) {     // 声明 model 用来传递数据
        List<Person> personList = ps.findAll();
        model.put("personList", personList);              // 通过这一步,JSP 页面就可以访问 personList
        return "/person/jPersonList";                    // 跳转到 jPersonList 页面
    }

    @RequestMapping("/person/toCreatePersonInfo")
    public String toCteatePersonInfo() {  // 跳转新增页面
        return "/person/jPersonCreate";
    }

    @RequestMapping("/person/toUpdatePersonInfo")
    public String toUpdatePersonInfo(Integer id, Model model) {  // 跳转修改页面
        Person p = ps.get(id);             // 获得要修改的记录,重新设置页面的值
        model.addAttribute("p", p);         // 将数据放到 response
        return "/person/jPersonUpdate";
    }

    @RequestMapping("/person/updatePersonList")
    public String updatePersonList(HttpServletRequest request, Person p, @RequestParam("photo") MultipartFile photeFile) throws IOException {  // 更新人员信息
        if (p.getId() == null) {
            ps.insert(p);   // 调用 Service 层方法,插入数据
        } else {
            String dir = request.getSession().getServletContext().getRealPath("/") + "/upload/";
            String fileName = photeFile.getOriginalFilename();                  // 原始的文件名
            String extName = fileName.substring(fileName.lastIndexOf("."));     // 扩展名
            fileName = fileName.substring(0, fileName.lastIndexOf(".")) + System.nanoTime() + extName;     // 防止文件名冲突
            FileUtils.writeByteArrayToFile(new File(dir + fileName), photeFile.getBytes());                // 写文件到 upload 目录

            p.setPhotoPath("/upload/" + fileName);

            ps.update(p);   // 调用 Service 层方法,更新数据
        }
        return "redirect:/person/all.action";        // 转向人员列表 action
    }

    @RequestMapping("/person/deleteById")
    public String deleteById(Integer id) {  // 删除单条记录
        ps.deleteById(id);
        return "redirect:/person/all.action";        // 转向人员列表 action
    }

    @RequestMapping("/person/deleteMuch")
    public String deleteMuch(String id) {  // 批量删除记录
        for (String delId : id.split(",")) {
            ps.deleteById(Integer.parseInt(delId));
        }
        return "redirect:/person/all.action";        // 转向人员列表 action
    }
}

第三步:在 jPersonUpdate.jsp 中添加 Spring 框架的标签,并重新配置 form 表单

<%-- Created by IntelliJ IDEA. User: 维C果糖 Date: 2017/1/30 Time: 18:00 To change this template use File | Settings | File Templates. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>PersonList</title>
</head>
<body>

<!-- 其中,modelAttribute 属性用于接收设置在 Model 中的对象,必须设置,否则会报 500 的错误 -->
<sf:form enctype="multipart/form-data" action="${pageContext.request.contextPath}/person/updatePersonList.action" modelAttribute="p" method="post">

    <sf:hidden path="id"/>

    <div style="padding:20px;">
        修改人员信息
    </div>

    <table>
        <tr>
            <td>姓名:</td>
            <td><sf:input path="name"/></td>
        </tr>
        <tr>
            <td>年龄:</td>
            <td><sf:input path="age"/></td>
        </tr>
        <tr>
            <td>图片:</td>
            <td><input type="file" name="photo" value=""/></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" name="btnOK" value="保存"/></td>
        </tr>
    </table>
</sf:form>

</body>
</html>

第四步:修改 jPersonList.jsp 页面,添加头像显示栏

<%-- Created by IntelliJ IDEA. User: 维C果糖 Date: 2017/1/30 Time: 18:20 To change this template use File | Settings | File Templates. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>PersonList</title>

    <script language="JavaScript"> /** * 批量提交方法 */ function deleteMuch() { document.forms[0].action = "${pageContext.request.contextPath}/person/deleteMuch.action"; document.forms[0].submit(); <!-- 手动提交 --> } </script>
</head>
<body>

    <form method="post">

        <div style="padding:20px;">
            <h2>人员列表</h2>
        </div>

        <div style="padding-left:40px;padding-bottom: 10px;">
            <a href="/springmvc-annotation/person/toCreatePersonInfo.action">新增</a>   <!-- 跳转路径 -->
            <a href="#" onclick="deleteMuch()">批量删除</a>   <!-- 调用 JavaScript -->
        </div>

        <table border="1">
            <tr>
                <td>选择</td>
                <td>头像</td>
                <td>编号</td>
                <td>姓名</td>
                <td>年龄</td>
                <td>操作</td>
            </tr>

            <c:forEach items="${personList}" var="p">
                <tr>
                    <td>
                        <input type="checkbox" name="id" value="${p.id}"/>
                    </td>
                    <td><img src="${pageContext.request.contextPath}${p.photoPath}"/></td>
                    <td>${p.id}</td>
                    <td>${p.name}</td>
                    <td>${p.age}</td>
                    <td>
                        <a href=/springmvc-annotation/person/toUpdatePersonInfo.action?id=${p.id}>修改</a>
                        <a href=/springmvc-annotation/person/deleteById.action?id=${p.id}>删除</a>
                    </td>
                </tr>
            </c:forEach>

        </table>
    </form>

</body>
</html>

第五步:在 springmvc-servlet.xml 中配置“文件上传视图解析器”

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd ">

    <!-- 声明注解开发方式 -->
    <mvc:annotation-driven/>

    <!-- 静态资源的管理 -->
    <mvc:resources location="/upload/" mapping="/upload/**"/>

    <!-- 包自动扫描 -->
    <context:component-scan base-package="spring.mvc.controller"/>

    <!-- 内部资源视图解析器,前缀 + 逻辑名 + 后缀 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 文件上传视图解析器,其名字必须为 multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/>   <!-- 限制页面上传文件最大为 10M -->
    </bean>
</beans>

在完成以上步骤后,启动 tomcat 服务器,然后访问 http://localhost:8080/springmvc-annotation/person/all.action,页面如下所示:

显示人员列表

然后,以编号为 0 的记录为例,进行测试,点击“修改”,页面如下所示:

修改人员信息

接下来,点击“选择文件”,进而选择咱们想要设置为头像的图片,点击“保存”,页面如下所示:

修改后页面回显

至此,图像的上传及显示功能,全部实现成功。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,049评论 18 139
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,334评论 0 10
  • 很久没拿起毛笔了,很久很久了。 JG兄每天都在练习书法。闲暇时,常常撺掇我:你也来写写呗!或说,我教你几笔吧!每次...
    墨语花开时阅读 320评论 4 4
  • 4天时间,仿佛,在另一个世界! 感冒了4天,身体还是完成了它要做的事,不再拖延。我感受到不一样的东西,深刻感受到了...
    陈奕奕阅读 137评论 0 0