博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring MVC 学习总结(六)——Spring+Spring MVC+MyBatis框架集成
阅读量:6584 次
发布时间:2019-06-24

本文共 39408 字,大约阅读时间需要 131 分钟。

 

与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC负责请求的转发和视图管理, MyBatis作为数据对象持久化引擎。这样搭配的优点是:轻量、自由度高、Spring与Spring MVC契合度更好。通过一个商品管理示例完成SSM框架的集成,可以将前面学习过的一些内容整合起来,使用到的知识包含:Spring、Spring MVC、MyBatis、JSR303校验、分页、文件上传、路径处理等。

一、新建一个基于Maven的Web项目

1.1、请勾选“Create a simple project”,创建一个简单的项目,这里不使用模板。也可以使用模板,选择WebApp,如果使用模板这里就不应该勾选。如下图所示:

1.2、填写好包名、项目名,选择打包类型为:war,如下图所示:

1.3、项目创建好后可能会发现有错误,选择项目,右键“属性properties”->"层面Project Facets"->"Java"修改版本号为1.7,默认为1.5或其它版本,先去掉“Dynamic Web Module”保存后再勾选,选择版本为3.0,再按箭头所示操作,步骤如下图所示:

1.4、删除WebContent后会发现项目的pom.xml文件报错,是因为找不到指定位置的web.xml文件引起的。再进入项目的属性,选择“Deployment Assembly”项目部署项,删除“src/test/java”、“src/test/resources”与“WebContent”目录,因为这三项不需要部署出去。

1.5、新建完成后发现有错误,是因为没有JavaEE Server Runtime引起的,在项目上右键属性选择“Java Build Path”项,点击“Add Library...”添加引用。也可以不选择Server Runtime可以在Maven中直接引用。目录结构如下所示:

提示:如果您是第一次使用Maven,详细的步骤请查看另一篇随笔:《》。

二、创建数据库与表

打开MySQL数据库,创建一个表,这里以goods表为例,一个用于存放商品的表,共4个字段id表示编号,name表示商品名称,picture表示图片,price表示价格。SQL脚本如下:

/*Navicat MySQL Data TransferSource Server         : localhostSource Server Version : 50536Source Host           : localhost:3306Source Database       : db1Target Server Type    : MYSQLTarget Server Version : 50536File Encoding         : 65001Date: 2016-07-20 10:13:58*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `goods`-- ----------------------------DROP TABLE IF EXISTS `goods`;CREATE TABLE `goods` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(200) NOT NULL,  `price` decimal(10,2) DEFAULT '0.00',  `picture` varchar(100) DEFAULT 'default.jpg',  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;-- ------------------------------ Records of goods-- ----------------------------INSERT INTO `goods` VALUES ('1', 'G7 中原G7三合一浓醇咖啡固体饮料1200', '66.50', '1.jpg');INSERT INTO `goods` VALUES ('2', '百草味东北松子200gx2袋 坚果炒货零', '42.90', '2.jpg');INSERT INTO `goods` VALUES ('3', '奈津香 桂圆干500gx2袋莆田特产5A桂', '39.90', '3.jpg');INSERT INTO `goods` VALUES ('4', '益达尊享护齿装草本40粒+冰柠40粒+西', '25.90', '4.jpg');INSERT INTO `goods` VALUES ('5', '猴坑茶业2016新茶原产地手工太平猴魁特', '168.00', '5.jpg');INSERT INTO `goods` VALUES ('6', '嘻鱿记 休闲零食 麻辣香辣奶香炭烧 5种', '39.80', '6.jpg');INSERT INTO `goods` VALUES ('7', '荣业鸿福五分瘦腊肠 香港土特产香肠腊味', '126.80', '7.jpg');INSERT INTO `goods` VALUES ('8', '蓓琳娜(BELLINA)3L PDO特级初榨橄榄油', '178.00', '8.jpg');INSERT INTO `goods` VALUES ('10', '荣业鸿福五分瘦腊肠 香港土特产香肠腊味', '30.60', 'b454b44f-868e-4efe-ae17-91e9e6a58390.jpg');

表结构如下所示:

三、添加依赖包

项目主要依赖的jar包有Spring核心包、Spring AOP包、Spring MVC包、MyBatis ORM包、MyBatis-Spring适配包、JSTL、JUnit、Log4j2等,具体的pom.xml文件如下:

4.0.0
com.zhangguo
SSMall
0.0.3
war
UTF-8
4.3.0.RELEASE
org.springframework
spring-context
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.aspectj
aspectjweaver
1.8.9
org.mybatis
mybatis-spring
1.3.0
org.springframework
spring-jdbc
${spring.version}
mysql
mysql-connector-java
5.1.38
org.apache.logging.log4j
log4j-core
2.6.1
org.mybatis
mybatis
3.4.1
junit
junit
4.10
c3p0
c3p0
0.9.1.2
javax.servlet
jstl
1.2
javax.servlet
javax.servlet-api
3.0.1
provided
javax.servlet.jsp
jsp-api
2.1
provided
com.fasterxml.jackson.core
jackson-core
2.5.2
com.fasterxml.jackson.core
jackson-databind
2.5.2
org.hibernate
hibernate-validator
5.2.2.Final
commons-io
commons-io
2.4
commons-fileupload
commons-fileupload
1.3.1
org.freemarker
freemarker
2.3.23

如果是第一次依赖相关的包,则需要下载时间,请耐心等待,如果下载失败请手动下载(http://search.maven.org/)后复制到本地的资源库中。依赖后的项目结果如下:

    

四、新建POJO实体层

为了实现与数据库中的books表进行关系映射新建一个Goods商品类,具体代码如下:

package com.zhangguo.ssmall.entities;import java.io.Serializable;import javax.validation.constraints.Min;import javax.validation.constraints.NotNull;import javax.validation.constraints.Pattern;/** * 商品实体 * */public class Goods implements Serializable {    /**     *      */    private static final long serialVersionUID = 1L;    /*     * 编号     */    private int id;    /*     * 名称     */    @Pattern(regexp="^[^><&#]{1,50}$",message="{pattern}")    @NotNull(message="{notNull}")    private String name;    /*     * 价格     */    @Min(value=1,message="必须大于或等于1")    private double price;    /*     * 图片     */    private String picture;        public Goods() {    }        public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }    public String getPicture() {        return picture;    }    public void setPicture(String picture) {        this.picture = picture;    }        @Override    public String toString() {        return "id:"+getId()+",name:"+getName()+",price:"+getPrice()+",picture:"+getPicture();    }}

为了实现校验,在成员变量上设置了一些注解信息。

五、新建MyBatis SQL映射层

这个项目中我们采用接口与xml结合的形式完成关系与对象间的映射,在接口中定义一些数据访问的方法,在xml文件中定义实现数据访问需要的sql脚本。商品数据访问映射接口如下:

package com.zhangguo.ssmall.mapper;import java.util.List;import org.apache.ibatis.annotations.Param;import com.zhangguo.ssmall.entities.Goods;public interface GoodsDAO {        /**     * 获得商品信息并分页     */    public List
getGoodsPager(@Param("skip") int skip,@Param("size") int size); /** * 获得单个商品通过编号 */ public Goods getGoodsById(int id); /** * 获得商品总数 */ public int getGoodsCount(); /* * 新增加商品 */ public int insert(Goods entity); /** * 删除商品 */ public int delete(int id); /** * 修改商品 */ public int update(Goods entity); }

为MyBatis ORM创建的映射文件GoodsMapper.xml(命名尽量都遵循一个规则,便于扫描,这里约定以实体名+Mapper)如下:

insert into goods(name,price,picture) values(#{name},#{price},#{picture});
delete from goods where id=#{id}
update goods set name=#{name},price=#{price},picture=#{picture} where id=#{id}

六、JUnit测试数据访问

为了保证数据访问正常,使用JUnit进行单元测试,在另一个源代码目录src/test/java下添加一个名为TestGoods的测试用例,编写完成的测试用例如下:

package com.zhangguo.ssmall.test;import java.util.List;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import com.zhangguo.ssmall.entities.Goods;import com.zhangguo.ssmall.mapper.GoodsDAO;import junit.framework.Assert;public class TestGoods{    @Test    public void getGoodsPagerTest() {        int skip=4;        int size=2;        SqlSession session=MyBatisUtil.getSession();        try {            GoodsDAO bookdao=session.getMapper(GoodsDAO.class);            List
goods=bookdao.getGoodsPager(skip, size); Assert.assertEquals(2, goods.size()); } finally { session.close(); } } @Test public void getGoodsByIdTest() { SqlSession session=MyBatisUtil.getSession(); try { GoodsDAO bookdao=session.getMapper(GoodsDAO.class); Goods goods=bookdao.getGoodsById(1); Assert.assertEquals(1, goods.getId()); } finally { session.close(); } } @Test public void getGoodsCountTest() { SqlSession session=MyBatisUtil.getSession(); try { GoodsDAO bookdao=session.getMapper(GoodsDAO.class); Assert.assertEquals(9, bookdao.getGoodsCount()); } finally { session.close(); } } @Test public void insertTest() { SqlSession session=MyBatisUtil.getSession(); try { Goods entity=new Goods(); entity.setName("正宗无锡阳山水蜜桃新鲜水果水密桃12个6斤装江浙沪皖顺丰包邮"); entity.setPrice(108); entity.setPicture("nopic.jpg"); GoodsDAO bookdao=session.getMapper(GoodsDAO.class); Assert.assertEquals(1, bookdao.insert(entity)); } finally { session.close(); } } @Test public void deleteTest() { SqlSession session=MyBatisUtil.getSession(); try { GoodsDAO bookdao=session.getMapper(GoodsDAO.class); Assert.assertEquals(1, bookdao.delete(12)); } finally { session.close(); } } @Test public void update() { SqlSession session=MyBatisUtil.getSession(); try { GoodsDAO bookdao=session.getMapper(GoodsDAO.class); Goods entity=bookdao.getGoodsById(12); entity.setName("正宗无锡阳山水蜜桃新鲜水果水密桃12个6斤装"); entity.setPrice(107); entity.setPicture("nopicture.jpg"); Assert.assertEquals(1, bookdao.update(entity)); } finally { session.close(); } } }

MyBatis访问数据库的工具类如下:

package com.zhangguo.ssmall.test;import java.io.InputStream;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;public abstract class MyBatisUtil {        public static SqlSessionFactory getSqlSessionFactory(){        // 获得环境配置文件流        InputStream config = MyBatisUtil.class.getClassLoader().getResourceAsStream("MyBatisCfg.xml");        // 创建sql会话工厂        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);        return factory;    }        //获得会话    public static SqlSession getSession(){        return getSqlSessionFactory().openSession(true);    }        /**     * 获得得sql会话     * @param isAutoCommit 是否自动提交,如果为false则需要sqlSession.commit();rollback();     * @return sql会话     */    public static SqlSession getSession(boolean isAutoCommit){        return getSqlSessionFactory().openSession(isAutoCommit);    }    }

MyBatis配置文件MyBatisCfg.xml如下所示:

 
View Code

配置文件中使用到了db.properties属性文件,该文件用于存放数据库连接信息,文件内容如下:

#mysqlmysql.driver=com.mysql.jdbc.Drivermysql.url=jdbc:mysql://localhost:3306/db1mysql.uid=rootmysql.password=root

运行测试,一切正常,测试结果如下: 

这里需要注意的是MyBatis配置文件的内容在后面与Spring整合后是会变化的,使用JUnit测试并未使用到Spring框架。

七、完成Spring整合MyBatis配置

7.1、在源代码的根目录下修改db.properties文件,用于存放数据库连接信息,文件内容如下:

#mysqlmysql.driver=com.mysql.jdbc.Drivermysql.url=jdbc:mysql://localhost:3306/db1mysql.uid=rootmysql.password=rootmysql.acquireIncrement=5mysql.initialPoolSize=10mysql.minPoolSize=5mysql.maxPoolSize=20

7.2、在源代码的根目录下新建 applicationContext.xml文件,用于整合MyBatis与Spring,非常关键,具体的内容如下:

从配置文件中可以看出第3点会话工厂配置中指定了MyBatis配置文件的位置与名称,其实也可以省去,在这里可以通过属性配置好。但个人认为当多个框架整合在一起时最后将配置文件分开,便于修改。修改后的MyBatisCfg.xml文件内容如下:

中间有一大段注释了,是因为MyBatis-Spring适配器已完成了这部分内容的工作,注释不删除的原因是因为JUnit测试时还要使用,其它也可以使用两个不同的文件。

八、配置web.xml加载Spring容器与MVC

修改web.xml文件,注册加载Spring容器所需的监听器;注册Spring MVC前置控制器Servlet,中间还设置了Servlet3.0上传所需的参数;添加了一个全局的编码过滤器。

index.jsp
Spring容器加载监听器
org.springframework.web.context.ContextLoaderListener
设置Spring加载时的配置文件位置,默认位置在WEB-INF/lib目录下
contextConfigLocation
classpath*:applicationContext.xml
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:springmvc-servlet.xml
1
5242880
20971520
0
springmvc
/
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
characterEncodingFilter
/*

在src/main/java源代码目录下添加applicationContext.xml文件,用于配置Spring,内容在上一节中已列出。

在src/main/java源代码目录下添加Spring MVC配置文件springmvc-servlet.xml,文件内容如下:

5
UTF-8
UTF-8
true
zh_CN
true,false
yyyy-MM-dd HH:mm:ss
HH:mm:ss
0.######
true

九、创建服务层 

在包com.zhangguo.ssmall.services下添加GoodsService.java文件,该文件是一个服务接口,内容如下:

package com.zhangguo.ssmall.services;import java.util.List;import com.zhangguo.ssmall.entities.Goods;/** * 商品业务接口 * */public interface GoodsService {    //分页    List
getGoodsPager(int pageNO, int size); //获得单个商品对象 Goods getGoodsById(int id); //获得商品总数 int getGoodsCount(); //添加 int insert(Goods entity); //删除单个 int delete(int id); //删除多个 int deletes(int[] ids); //更新 int update(Goods entity);}

在包com.zhangguo.ssmall.services下添加类GoodsServiceImpl.java,实现接口GoodsService,用于完成商品业务逻辑,由于是示例代码所以比较空;中间使用了两个注解一个是@Service,用于提供给需要服务的类自动装配,当Spring IOC容器启动时被扫描到该类型会自动添加实例到Spring容器中;另一个注解是@Resource用于完成自动装配功能,在Spring容器中找到GoodsDAO类型的对象,代码如下:

package com.zhangguo.ssmall.services;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.zhangguo.ssmall.entities.Goods;import com.zhangguo.ssmall.mapper.GoodsDAO;/** * 商品业务实现 *  *///自动添加到Spring容器中@Servicepublic class GoodsServiceImpl implements GoodsService{    //自动装配    @Resource    GoodsDAO goodsdao;        //分页    @Override    public List
getGoodsPager(int pageNO, int size) { int skip=(pageNO-1)*size; return goodsdao.getGoodsPager(skip, size); } //获得单个产品对象 @Override public Goods getGoodsById(int id) { return goodsdao.getGoodsById(id); } //获得商品总数 @Override public int getGoodsCount() { return goodsdao.getGoodsCount(); } //添加 @Override public int insert(Goods entity) { return goodsdao.insert(entity); } //删除单个 @Override public int delete(int id) { return goodsdao.delete(id); } //删除多个 @Override public int deletes(int[] ids) { int rows=0; for (int id : ids) { rows+=delete(id); } return rows; } //更新 @Override public int update(Goods entity) { return goodsdao.update(entity); }}

十、完成商品管理功能

10.1、商品列表与分页

定义GoodsController控制器,映射访问路径,需要使用到的商品服务使用自动装配完成,代码如下:

package com.zhangguo.ssmall.controllers;import javax.annotation.Resource;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 com.zhangguo.ssmall.services.GoodsService;@Controller@RequestMapping("/goods")public class GoodsController {        @Resource    GoodsService goodsService;        /*     * 产品列表与分页Action     */    @RequestMapping("/list")    public String list(Model model,@RequestParam(required=false,defaultValue="1") int pageNO){        int size=5;        model.addAttribute("size",size);        model.addAttribute("pageNO",pageNO);        model.addAttribute("count",goodsService.getGoodsCount());        model.addAttribute("goods", goodsService.getGoodsPager(pageNO, size));        return "goods/list";    }    }

参数size表示每页记录数,pageNO表示当前页号,处于第几页,count表示总记录数。

在views/jstl/goods目录下添加视图list.jsp页面,页面的内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
" type="text/css" rel="stylesheet" />商品管理

商品管理

编号 产品名 价格 类型 操作
${entity.id} ${entity.name} " height="40"/> ${entity.price} 删除 编辑

添加

${message}

" >
" type="text/css" rel="stylesheet" />
" >

为了实现分页,添加了一个jQuery插件pagination,该插件的详细参数如下所示:

 
View Code

测试运行结果:

页面中有一个简单处理加载图片失败的事件,当图片加载出错时使用default.jpg图,如编号为38的图片就是默认图。

11.2、删除与多删除功能

为了实现删除与多删除功能,修改控制器,增加2个action,delete请求处理方法用于删除单个记录,id是路径变量指定要删除的商品编号;pageNO是请求参数,保持状态的目的是为了删除后让页面继续停留在某一页,不过这里有问题的是当某一页的内容只有一条记录里就需要重新计算了;rediredtAttributes是为了保持重定向后的message值。

/*     * 删除单个产品对象Action     */    @RequestMapping("/delete/{id}")    public String delete(Model model,@PathVariable int id,@RequestParam(required=false,defaultValue="1") int pageNO,RedirectAttributes redirectAttributes){        if(goodsService.delete(id)>0)        {            redirectAttributes.addFlashAttribute("message", "删除成功!");        }else{            redirectAttributes.addFlashAttribute("message", "删除失败!");        }        return "redirect:/goods/list?pageNO="+pageNO;    }        /*     * 删除多个产品对象Action     */    @RequestMapping("/deletes")    public String deletes(Model model,@RequestParam int[] id,@RequestParam(required=false,defaultValue="1") int pageNO,RedirectAttributes redirectAttributes){        //执行删除        int rows=goodsService.deletes(id);        if(rows>0)        {            redirectAttributes.addFlashAttribute("message", "删除"+rows+"行记录成功!");        }else{            redirectAttributes.addFlashAttribute("message", "删除失败!");        }        return "redirect:/goods/list?pageNO="+pageNO;    }

为了配合删除,修改list.jsp页面,修改后的list.jsp页面如下所示:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
" type="text/css" rel="stylesheet" />商品管理

商品管理

" method="post">
编号 产品名 价格 类型 操作
${entity.id} ${entity.name} " height="40"/> ${entity.price} delete/${entity.id}?pageNO=${pageNO}" class="abtn">删除 edit/${entity.id}" class="abtn">编辑 upPicture/${entity.id}" class="abtn">上传

添加

${message}

" >
" type="text/css" rel="stylesheet" />
" >

运行结果如下所示:

基中的多删除功能可以改进为一次性让数据库删除完成。

11.3、新增商品功能

在控制器中添加2个action,一个是add用于完成添加页面展示,一个是addSave用于完成添加保存处理,代码如下:

/*     * 添加商品     */    @RequestMapping("/add")    public String add(Model model){        model.addAttribute("entity", new Goods());        return "goods/add";    }        /*     * 添加商品保存     */    @RequestMapping("/addSave")    public String addSave(Model model,@ModelAttribute("entity") @Valid Goods entity,BindingResult bindingResult){        //如果模型中存在错误        if(!bindingResult.hasErrors()){            if(goodsService.insert(entity)>0)            {                return "redirect:/goods/list";                }        }        model.addAttribute("entity", entity);        return "goods/add";    }

这里有一个问题是因为使用了JSR303校验,当保存对象是需要在参数前注解@ModelAttribute("entity") @Valid,用于激活校验,否则页面将不会有错误展示,非常奇怪的问题;我在第五章中并没有发现该问题。

为了配合Bean Validation,定义的Goods Bean需要注解,内容如下:

/*     * 名称     */    @Pattern(regexp="^[^><&#]{1,50}$",message="{pattern}")    @NotNull(message="{notNull}")    private String name;    /*     * 价格     */    @Min(value=1,message="必须大于或等于1")    private double price;

这里的错误消息来源一个是直接写在注解中,另一个来自消息文件;{pattern}来自消息文件ValidationMessages.properties,在src/main/java目录下新建该文件,文件内容如下:

pattern=格式错误notNull=不允许为空

这里需注意的是,默认情况下中文会显示成utf-8编码格式如:

pattern=\u683C\u5F0F\u9519\u8BEFnotNull=\u4E0D\u5141\u8BB8\u4E3A\u7A7A

为了正常显示,可以安装一个插件,让属性文件支持正常显示中文,插件名称是properties-editor,点击“Helo”->“Marketplace”,搜索插件名称,显示内容如下:

点击Install,进入下一步:

完成后在properties文件上右键选择“Open With”,具体步骤如下:

在views/jstl/goods目录下新增加add.jsp页面,页面内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
" type="text/css" rel="stylesheet" />新增商品

新增商品

商品

${message}

" class="abtn out">返回列表

运行结果:

11.4、编辑商品功能

与新增加类似,在控制器下新增两个action,一个用于展示编辑,有一个用于执行编辑后保存,代码如下所示:

/*     * 编辑商品     */    @RequestMapping("/edit/{id}")    public String edit(Model model,@PathVariable int id){        model.addAttribute("entity", goodsService.getGoodsById(id));        return "goods/edit";    }        /*     * 编辑商品保存     */    @RequestMapping("/editSave")    public String editSave(Model model,@ModelAttribute("entity") @Valid Goods entity,BindingResult bindingResult){        //如果模型中存在错误        if(!bindingResult.hasErrors()){            if(goodsService.update(entity)>0)            {                return "redirect:list";                }        }        model.addAttribute("entity", entity);        return "/goods/edit";    }

在views/jstl/goods目录下新增加edit.jsp页面,页面内容如下:

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
" type="text/css" rel="stylesheet" />编辑商品" />

编辑商品

商品

${message}

返回列表

运行结果:

11.5、上传图片功能

这里使用Servlet3.0实现文件上传,相关配置已经在前面的配置文件中设置好了,在控制器中增加两个action,代码如下:

/**     * 上传图片     */    @RequestMapping("/upPicture/{id}")    public String upPicture(Model model,@PathVariable int id){        model.addAttribute("entity", goodsService.getGoodsById(id));        return "goods/upfile";    }        /*     * 上传图片保存     */    @RequestMapping("/upPictureSave/{id}")    public String upPictureSave(Model model,@PathVariable int id,MultipartFile picFile,HttpServletRequest request){        Goods entity=goodsService.getGoodsById(id);        //如果选择了文件        if(picFile!=null){             //如果文件大小不为0            if(picFile.getSize()>0){                //获得上传位置                String path=request.getServletContext().getRealPath("/images");                //生成文件名                String filename=UUID.randomUUID().toString()+picFile.getOriginalFilename().substring(picFile.getOriginalFilename().lastIndexOf("."));                File tempFile=new File(path, filename);                try {                    //保存文件                    picFile.transferTo(tempFile);                    //更新数据                    entity.setPicture(filename);                    goodsService.update(entity);                    //转向列表页                    return "redirect:/goods/list";                    } catch (Exception e) {                    e.printStackTrace();                }            }        }        model.addAttribute("entity", entity);        return "goods/upfile";    }

在views/jstl/goods目录下新增加upfile.jsp页面,页面内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
" type="text/css" rel="stylesheet" />上传图片

上传图片

" method="post" enctype="multipart/form-data">
商品

${entity.name}

${entity.price}

${message}

" class="abtn out">返回列表

运行结果如下:

11.6、日志、首页、样式与最终的控制器

为了将MyBatis与Hibernate Validation的日志信息展示在控制中,需要添加log4j2的引用,这部分内容在pom.xml中已配置完成了,另外在项目的根目录下需要添加一个log4j2的配置文件log4j2.xml,内容如下:

在webapp目录下添加index.jsp,首页是这个程序的入口,只完成了转发功能,页面内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

所有页面基本都引用了同一个样式表styles/main.css文件,文件内容如下:

 
View Code

最终的控制器GoodsController.java文件内容如下:

package com.zhangguo.ssmall.controllers;import java.io.File;import java.util.UUID;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.validation.Valid;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.validation.BindingResult;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.zhangguo.ssmall.entities.Goods;import com.zhangguo.ssmall.services.GoodsService;@Controller@RequestMapping("/goods")public class GoodsController {        @Resource    GoodsService goodsService;        /*     * 产品列表与分页Action     */    @RequestMapping("/list")    public String list(Model model,@RequestParam(required=false,defaultValue="1") int pageNO){        int size=5;        model.addAttribute("size",size);        model.addAttribute("pageNO",pageNO);        model.addAttribute("count",goodsService.getGoodsCount());        model.addAttribute("goods", goodsService.getGoodsPager(pageNO, size));        return "goods/list";    }        /*     * 删除单个产品对象Action     */    @RequestMapping("/delete/{id}")    public String delete(Model model,@PathVariable int id,@RequestParam(required=false,defaultValue="1") int pageNO,RedirectAttributes redirectAttributes){        if(goodsService.delete(id)>0)        {            redirectAttributes.addFlashAttribute("message", "删除成功!");        }else{            redirectAttributes.addFlashAttribute("message", "删除失败!");        }        return "redirect:/goods/list?pageNO="+pageNO;    }        /*     * 删除多个产品对象Action     */    @RequestMapping("/deletes")    public String deletes(Model model,@RequestParam int[] id,@RequestParam(required=false,defaultValue="1") int pageNO,RedirectAttributes redirectAttributes){        //执行删除        int rows=goodsService.deletes(id);        if(rows>0)        {            redirectAttributes.addFlashAttribute("message", "删除"+rows+"行记录成功!");        }else{            redirectAttributes.addFlashAttribute("message", "删除失败!");        }        return "redirect:/goods/list?pageNO="+pageNO;    }        /*     * 添加商品     */    @RequestMapping("/add")    public String add(Model model){        model.addAttribute("entity", new Goods());        return "goods/add";    }        /*     * 添加商品保存     */    @RequestMapping("/addSave")    public String addSave(Model model,@ModelAttribute("entity") @Valid Goods entity,BindingResult bindingResult){        //如果模型中存在错误        if(!bindingResult.hasErrors()){            if(goodsService.insert(entity)>0)            {                return "redirect:/goods/list";                }        }        model.addAttribute("entity", entity);        return "goods/add";    }        /*     * 编辑商品     */    @RequestMapping("/edit/{id}")    public String edit(Model model,@PathVariable int id){        model.addAttribute("entity", goodsService.getGoodsById(id));        return "goods/edit";    }        /*     * 编辑商品保存     */    @RequestMapping("/editSave")    public String editSave(Model model,@ModelAttribute("entity") @Valid Goods entity,BindingResult bindingResult){        //如果模型中存在错误        if(!bindingResult.hasErrors()){            if(goodsService.update(entity)>0)            {                return "redirect:list";                }        }        model.addAttribute("entity", entity);        return "/goods/edit";    }        /**     * 上传图片     */    @RequestMapping("/upPicture/{id}")    public String upPicture(Model model,@PathVariable int id){        model.addAttribute("entity", goodsService.getGoodsById(id));        return "goods/upfile";    }        /*     * 上传图片保存     */    @RequestMapping("/upPictureSave/{id}")    public String upPictureSave(Model model,@PathVariable int id,MultipartFile picFile,HttpServletRequest request){        Goods entity=goodsService.getGoodsById(id);        //如果选择了文件        if(picFile!=null){             //如果文件大小不为0            if(picFile.getSize()>0){                //获得上传位置                String path=request.getServletContext().getRealPath("/images");                //生成文件名                String filename=UUID.randomUUID().toString()+picFile.getOriginalFilename().substring(picFile.getOriginalFilename().lastIndexOf("."));                File tempFile=new File(path, filename);                try {                    //保存文件                    picFile.transferTo(tempFile);                    //更新数据                    entity.setPicture(filename);                    goodsService.update(entity);                    //转向列表页                    return "redirect:/goods/list";                    } catch (Exception e) {                    e.printStackTrace();                }            }        }        model.addAttribute("entity", entity);        return "goods/upfile";    }}

十二、总结

通个该示例将前面几章的内容整合起来,巩固了前几章的内容;示例中还可以尝试使用FreeMarker视图;示例中没有前端验证都是后台验证,可以使用jQuery扩展插件Validate实现前端校验;有些功能可以结合AJAX完成更加合理;路径是要非常小心的,后台重定向时,前台提交表单的路径,可以使用base标签和c:url。内容比较简单,适合初学,只是希望能起到抛砖引玉、以小见大的作用,谢谢阅读!

十三、示例下载与预览

转载于:https://www.cnblogs.com/liujiandejava/p/9359619.html

你可能感兴趣的文章
JSON for Modern C++ 3.6.0 发布
查看>>
我的友情链接
查看>>
监听在微信中打开页面时的自带返回按钮事件
查看>>
第一个php页面
查看>>
最优化问题中黄金分割法的代码
查看>>
在JS中使用Ajax
查看>>
Jolt大奖获奖图书
查看>>
ubuntu 16.04 安装PhpMyAdmin
查看>>
设置分录行按钮监听事件
查看>>
23种设计模式(1):单例模式
查看>>
socket 编程入门教程(五)UDP原理:4、“有连接”的UDP
查看>>
Jquery获取iframe中的元素
查看>>
Laravel 学习笔记5.3之 Query Builder 源码解析(下)
查看>>
Struts2简单入门实例
查看>>
2012CSDN年度博客之星评选http://vote.blog.csdn.net/item/blogstar/xyz_lmn
查看>>
BZOJ 4037 [HAOI2015]数字串拆分 ——动态规划
查看>>
SpringBoot实战总汇--详解
查看>>
2018年7月1日笔记
查看>>
尝试使用iReport4.7(基于Ubuntu Desktop 12.04 LTS)
查看>>
子元素应该margin-top为何会影响父元素【转】
查看>>