SSM框架(Springmv+Spring+mybatis)

🍓导包

  1. SpringIOC核心依赖4个包
  2. Springmvc的两个web
  3. SpringAOP4个包
  4. Spring-JDBC
  5. mysql数据库的依赖
  6. c3p0数据库连接池的2个依赖
  7. mybatis的包和Spring支持mybatis的包
  8. 前端可能会使用的jstljstl-api以及standard
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

         <!--https://mvnrepository.com/artifact/org.aopalliance/com.springsource.org.aopalliance-->
        <dependency>
            <groupId>org.aopalliance</groupId>
            <artifactId>com.springsource.org.aopalliance</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!--https://mvnrepository.com/artifact/org.springframework/spring-tx-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--spring整合mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>mchange-commons-java</artifactId>
            <version>0.2.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl-api</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/taglibs/standard -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!--返回json格式的数据-->
        <dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.12.4</version>
		</dependency>
		<!-- xml序列化工具,类似与JAXB,JAXB依赖jdk内部实现,这个功能更丰富 -->
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
			<version>2.12.4</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>2.12.4</version>
		</dependency>

🍓创建配置文件

🍒db.properties数据库配置文件
  1. 数据库驱动
  2. 数据库访问url
  3. 数据库用户名
  4. 数据库密码
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test8?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=cqrjxk39

注意:
xml中写数据库访问url时,“&”会变成"&amp;",这可能是由xml的编码规则决定的,在xml文件中有以下几类字符要进行转义替换:

&lt;<小于号
&gt;>大于号
&amp;&
&apos;单引号
&quot;"双引号
🍒mybatis-cfg配置
  1. 打印sql语句
  2. 实例类别名配置
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--打印日志-->
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <!--指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,不区分大小写-->
        <package name="com.spring.pojo"></package>
    </typeAliases>
</configuration>
🍒application-context.xml配置
  1. 配置组件扫描,完成bean管理
  2. 加载配置文件db.properties
  3. 配置c3p0数据库连接池
  4. 配置mybatis
  5. 配置事务管理器
  6. 开启事务注解
<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.0.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    		 http://www.springframework.org/schema/aop
     		http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
           ">
    <context:component-scan base-package="com.spring"></context:component-scan>

    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="mapperLocations" value="classpath:com/spring/dao/*.xml"></property>
        <property name="configLocation" value="classpath:mybatis-cfg.xml"></property>
    </bean>
    <!--Spring配置mapper-->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.spring.dao"></property>
        <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

</beans>

注意: 使用eclipse编译器编写此段代码很容易会出现Cannot find the declaration of element 'beans'这个错误,在这种情况下可以使用本地对象,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           classpath:/org/springframework/beans/factory/xml/spring-beans.xsd
           http://www.springframework.org/schema/context
           classpath:/org/springframework/context/config/spring-context.xsd
            http://www.springframework.org/schema/tx
            classpath:/org/springframework/transaction/config/spring-tx.xsd
    		 http://www.springframework.org/schema/aop
     		classpath:/org/springframework/aop/config/spring-aop.xsd">

使用classpath:+路径,路径去本地导入的jar包中去找

🍒springmvc配置
  1. 配置注解驱动
  2. 视图解析器
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1.约束文件 -->
<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 ">
    
    <!--注解驱动,使用注解驱动器可以加载处理器映射器RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter-->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!--虽说在application-context.xml配置了注解扫描,但是还是有可能会扫不到@Controller,导致访问方法时出现404的错误,所以我们尽量在springmvc中再配一次针对controller包的扫描-->
    <context:component-scan base-package="com.spring.controller"></context:component-scan>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>
🍒web.xml配置
  1. 配置Spring的监听器(用来读取配置文件application-context.xml
  2. 配置前端控制器
  3. 配置POST提交编码格式(防止乱码)
	<listener>
        <!--web依赖下面的context包下的ContextLoaderListener-->
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application-context.xml</param-value>
    </context-param>
    
    <!--配置前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--默认找/WEB-INF/[servlet的名称(springmvc)]-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <!--配置拦截规则
           1. /*  拦截所有(jsp,js,png,css)
           2. *.action  *.do  拦截以do,action结尾的请求  (面向后台)
           3. /   拦截所有(不包括jsp,其他都拦截)        (面向前台)
    -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
	<!--防止前端传递过来的参数出现乱码,如果有乱码添加以下代码-->
	<filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>
🍒springmvc对静态资源处理

web.xml的拦截为“/”或者“/*”拦截所有的时候,前端的CSSjs等页面同样会被拦截,所以我们需要在springmvc.xml配置中对静态资源做一定的处理

<mvc:resources location="/CSS/" mapping="/CSS/**"></mvc:resources>
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>

🍓Springmvc转换日期格式或者字符串样式

Springmvc中配置转换工厂,转换器主要由springmvc的适配器来完成
springmvc配置文件配置

	<!--注解驱动,使用注解驱动器可以加载处理器映射器RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter-->
    <mvc:annotation-driven conversion-service="ConversionServiceFactoryBean"></mvc:annotation-driven>

    <!--配置Conveter转换器,转换工厂(日期格式、去掉前后空格)-->
    <bean id="ConversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!--配置多个转换器-->
        <property name="converters">
            <list>
                <!--自定义转换器-->
                <bean class="com.spring.converter.DateConverter"></bean>
            </list>
        </property>
    </bean>

自定义转换器,实现Converter接口

import org.springframework.core.convert.converter.Converter;
//String为需要转换的目标的类型,Timestamp是被转换的目标类型
public class DateConverter implements Converter<String, Timestamp> {
    @Override
    public Timestamp convert(String s) {
        try {
            if( s != null){
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy:MM-dd HH_mm-ss");
                Timestamp parse = (Timestamp) simpleDateFormat.parse(s);
                return parse;
            }
        }catch (Exception e){

        }
        return null;
    }
}

🍓高阶参数绑定

🍒数组

数组大多应用于多选删除的场合
例如:
前端

<!--引入jstl的jar包,并且定义对象为c-->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<form action="${pageContext.request.contextPath}/deletes.action" method="post">
	商品列表:
	<table width="100%" border=1>
		<tr>
			<td>商品名称</td>
			<td>商品价格</td>
			<td>生产日期</td>
			<td>商品描述</td>
			<td>操作</td>
		</tr>
		<c:forEach items="${itemList }" var="item">
			<tr>
				<td><input type="checkbox" name="ids" value="${item.id}"></td>
				<td>${item.name }</td>
				<td>${item.price }</td>
				<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
				<td>${item.detail }</td>
				
				<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
			
			</tr>
		</c:forEach>
	
	</table>
	<input type="submit" value="删除">
</form>

后端:

	//produces参数是为了防止后端传递给前端数据中有中文时会出现乱码
	@RequestMapping(value = "/deletes.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8")
    public String deletes(Integer[] ids){
        for (Integer id:ids){
            itemService.delete(id);
        }
        return "redirect:/itemList.action";
    }
🍒list

list集合一般用于批量修改
例如:

  1. 后端实体类中必须要有list集合,且泛型为该实体类

  2. 前端代码:

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <form action="${pageContext.request.contextPath}/updates.action" method="post">
    商品列表:
    <table width="100%" border=1>
    	<tr>
    		<td>商品名称</td>
    		<td>商品价格</td>
    		<td>生产日期</td>
    		<td>商品描述</td>
    		<td>操作</td>
    	</tr>
    	<c:forEach items="${itemList }" var="item" varStatus="s">
    		<tr>
    			<td><input type="hidden" name="items[${s.index}].id" value="${item.id}"></td>
    			<td><input type="text" name="items[${s.index}].name" value="${item.name }"></td>
    			<td><input type="text" name="items[${s.index}].price" value="${item.price }"></td>
    			<td><input type="text" name="items[${s.index}].detail" value="${item.detail }"></td>
    			<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
    		</tr>
    	</c:forEach>
    </table>
    <input type="submit" value="修改">
    </form>
    
  3. 后端

    	@RequestMapping(value = "/updates.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8")
        public String updates(Item item){
            List<Item> items = item.getItems();
            for (int i= 0; i < items.size(); i++){
                itemService.update(items.get(i));
            }
            return "redirect:/itemList.action";
        }
    

🍓springmvc的注解

  • @RequestMapping:表示方法返回的是页面或者是重定向,可以放在方法上,也可以放在类上

    • value:访问路径,是数组,可以实现多请求,多个url可以使用大括号括起来,值之间以“,”隔开
    • method:提交方式,常用的两个值为RequestMethod.POSTRequestMethod.GET,默认值为get,也是数组,支持多种提交方式也是用大括号括起来,值之间以“,”隔开
    • produces:后端传递前端的参数格式,防止参数中含有中文会出现乱码问题
  • @ResponseBody:一般与@RequestMapping配套使用,返回json数据

  • @RestController:放在类上,相当于@ResponseBody+@Controller,表示该类下所有的方法都返回的是json数据

  • @CrossOrigin(allowCredentials="true", allowedHeaders="*")Spring4.2及以上版本支持,放在类上,用于解决跨域问题。4.2以下版本可以使用拦截器来解决跨域问题,文章下面讲述拦截器时有提到,里面的参数配合前端ajax的属性xhrFields: {withCredentials: true},可以保证跨域请求获取sessionId的一致性

🍓异常处理器(HandlerExceptionResolver)

springmvc在处理请求过程中会负责捕获dao,service,controller层的异常信息,并交由自定义异常处理器处理,异常分为预期异常(自己可以预测到的)和运行时异常(未知的)

  1. 创建预期异常类,并继承Exception

    @Data
    public class MessageException extends Exception {
    
        private String msg;
    
        public MessageException(String msg){
            this.msg = msg;
        }
    }
    
  2. dao,service,controller你能预测到可能会发生此异常的地方抛出此异常

    		if(items == null){
                throw new MessageException("商品信息不能为空");
            }
    
  3. 创建自定义异常类,并实现org.springframework.web.servlet.HandlerExceptionResolver接口,并使用注解将其纳入springbean管理

    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.stereotype.Component;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class ExceptionResolver implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
            ModelAndView modelAndView = new ModelAndView();
            //判断异常类型
            if(e instanceof MessageException){
                //预期异常
                MessageException messageException = (MessageException)e;
                modelAndView.addObject("error",(messageException.getMsg()));
            }else{
                //运行时异常
                modelAndView.addObject("error","未知异常");
                System.out.println(o);
                System.out.println(e);
            }
            modelAndView.setViewName("error");
            return modelAndView;
        }
    }
    

🍓上传文件

  • Deployment创建文件夹upload(名字随便取)

  • 配置tomcat
    在这里插入图片描述

  • 添加文件上传依赖

    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    
  • 前端

    • 不管你是上传图片还是上传文件,form表单的属性里面必须要有enctype="multipart/form-data"
    • 设置回显时,必须要先判断,否则图片可能没有,显示不出来
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<form id="itemForm"	action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data">
	<input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
	<table width="100%" border=1>
		<tr>
			<td>商品名称</td>
			<td><input type="text" name="name" value="${item.name }" /></td>
		</tr>
		<tr>
			<td>商品价格</td>
			<td><input type="text" name="price" value="${item.price }" /></td>
		</tr>

		<tr>
			<td>商品生产日期</td>
			<td><input type="text" name="createtime"
				value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
		</tr>
		<tr>
			<td>商品图片</td>
			<td>
				<c:if test="${item.pid !=null}">
					<!--判断图片是否存在,这边的路径必须与你在上面配置tomcat的路径一致-->
					<img src="/pid/${item.pid}" width=100 height=100/>
					<br/>
				</c:if>
				<input type="file"  name="pictureFile"/>
			</td>
		</tr>
		<tr>
			<td>商品简介</td>
			<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
			</td>
		</tr>
		<tr>
			<td colspan="2" align="center"><input type="submit" value="提交" />
			</td>
		</tr>
	</table>
</form>
  • 后端
    • 设置图片的名字
    • 获取文件后缀名
    • 保存到磁盘
    • 保存到数据库(只需保存图片名即可,因为前端有配置完整的路径)
@RequestMapping(value = "/updateitem.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
public String updateitem(Item item, MultipartFile pictureFile) throws IOException {
    //        设置图片名字,防止名字重复
    String s = UUID.randomUUID().toString().replaceAll("-", "");
    //获取文件扩展名
    String extension = FilenameUtils.getExtension(pictureFile.getOriginalFilename());
    //        保存图片到D盘
    pictureFile.transferTo(new File("D:\\upload\\"+s+"."+extension));
    //保存到数据库
    item.setPid(s+"."+extension);

    itemService.update(item);
    return "redirect:/itemEdit.action?id="+item.getId();
}

🍓json数据交互

  • 导入解析json数据的三个包

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.8</version>
    </dependency>
    
  • 导入jquery

  • 前端ajax编写

    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    	<title>修改商品信息</title>
    	<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.4.4.min.js"></script>
    	<script type="text/javascript">
    		$(function () {
    			// alert(1);
    			var params = '{"id":10,"name":"测试商品","price":99.9,"detail":"测试商品描述","pid":"123456.jpg"}';
    			$.ajax({
    				url:"${pageContext.request.contextPath}/json.action",
    				data:params,
    				contentType:"application/json;charset=UTF-8",//发送的数据格式
    				type:"post",
    				dataType:"json",//回调的数据也是json数据
    				success:function (data) {
    					alert(data.name);
    				}
    			})
    		})
    	</script>
    </head>
    
  • 创建一个类封装json数据

  • 接收json数据,并返回json数据到前端

    	@ResponseBody
        @RequestMapping(value = "/json.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8")
        public Item json(@RequestBody Item item){
            System.out.println("json来了");
            System.out.println(item);
            return item;
        }
    

🍓RestFu的开发风格

如果前端的请求url的方式如下所示,请求参数直接放在url中,并没有使用?+键值对的形式,那么后端的代码为
前端:

<td><a href="${pageContext.request.contextPath }/itemEdit/${item.id}.action">修改</a></td>

后端:

@RequestMapping(value = "/itemEdit/{id}.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
   public String toEditItem(@PathVariable int id,Model model){
       Item item = new Item();
       item.setId(id);
       List<Item> items = itemService.find(item);
       if(items.size() != 0){
           model.addAttribute("item",items.get(0));
       }
       return "editItem";
   }

🍓拦截器

🍒访问顺序

用户访问——>拦截器方法前——>执行controller层方法——>拦截器方法后——>拦截器页面渲染——>用户

🍒拦截器的使用
  • 创建拦截器类,并实现org.springframework.web.servlet.HandlerInterceptor接口,可以创建多个

    import org.springframework.lang.Nullable;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class Interceptor1 implements HandlerInterceptor {
        //方法前,true表示放行,false表示拦截
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        	//Spring4.2以下版本解决跨域问题
           String originHeader = request.getHeader("Origin");
           response.setHeader("Access-Control-Allow-Origin", originHeader);
           response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");  
           response.setHeader("Access-Control-Max-Age", "0");  
           response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");  
           response.setHeader("Access-Control-Allow-Credentials", "true");  
           response.setHeader("XDomainRequestAllowed","1");   
           response.setHeader("XDomainRequestAllowed","1");
            return true;
        }
    
        //方法后
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    
        }
    
        //页面渲染
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    
        }
    }
    
  • springmvc配置文件中配置拦截器

    <mvc:interceptors>
        <!--自定义拦截器,可以定义多个-->
        <mvc:interceptor>
            <!--/**指拦截所有-->
            <mvc:mapping path="/**"/>
            <bean class="com.spring.interceptor.Interceptor1"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <!--/**指拦截所有-->
            <mvc:mapping path="/**"/>
            <bean class="com.spring.interceptor.Interceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    
🍒拦截器的执行流程
  • 方法前preHandle按照拦截器定义的顺序调用
  • 方法后postHandle按照拦截器定义的逆序调用,并且只有当方法前preHandle全部返回true才会调用
  • 页面渲染afterCompletion按照拦截器定义的逆序调用,只要其所在的拦截器的方法前preHandle返回true就会调用
🍒实际操作

前端登录页面:

<form action="${pageContext.request.contextPath}/login.action" method="post">
    <input type="text" name="username"><br />
    <input type="submit" value="登录">
</form>

后端:

  1. 前往登录页面

  2. 登录后保存用户名到session,并跳转到其他页面

    //前往登录页面
    @RequestMapping(value = "/login.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
    public String tologin(){
        return "login";
    }
    
    //登录后保存跳转
    @RequestMapping(value = "/login.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8")
    public String login(String username, HttpSession session){
        //将用户名保存到session
        session.setAttribute("username",username);
        return "redirect:/itemList.action";
    }
    

拦截器方法1:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String requestURI = request.getRequestURI();
    if(!requestURI.equals("/Demo32/login.action")){
        //表示如果不是访问登录页面的请求,那么就要判断他有没有登录
        String username = (String) request.getSession().getAttribute("username");
        if(username == null){
            //表示如果没有登录,将其拦截并打回登录页面
            response.sendRedirect(request.getContextPath()+"/login.action");
            return false;
        }
    }
    //以上条件都符合后会返回true,放行
    return true;
}

🍓分页

分页两个比较重要的类,其中一个是PageHelper,另外一个是PageInfo

  1. 导入分页包

    <!-- https://mvnrepository.com/artifact/com.github.miemiedev/mybatis-paginator -->
    <dependency>
        <groupId>com.github.miemiedev</groupId>
        <artifactId>mybatis-paginator</artifactId>
        <version>1.2.15</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.2</version>
    </dependency>
    
  2. 配置application-context.xml配置文件

    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="mapperLocations" value="classpath*:com/hospital/dao/*.xml"></property>
        <property name="configLocation" value="classpath:mybatis-cfg.xml"></property>
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <value>
                            <!--支持的数据库类型-->
                            helperDialect=mysql
                            reasonable=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>
    </bean>
    
  3. daoservice层编写(略)

  4. 分析PageInfo类的属性

    	//当前页
    	private int pageNum;
    	//每页显示的记录数
        private int pageSize;
        //当前页面的记录数
        private int size;
        //起始页
        private int startRow;
        //尾页
        private int endRow;
        //总记录数
        private long total;
        //总页数
        private int pages;
        //结果集
        private List<T> list;
        //前一页
        private int prePage;
        //下一页
        private int nextPage;
        //是否为第一页
        private boolean isFirstPage;
        //是否为最后一页
        private boolean isLastPage;
        //是否有前一页
        private boolean hasPreviousPage;
        //是否有下一页
        private boolean hasNextPage;
        //导航页码数
        private int navigatePages;
        //所有导航页号
        private int[] navigatepageNums;
        //导航起始页
        private int navigateFirstPage;
        //导航最后一页
        private int navigateLastPage;
    
  5. 前端(参考)

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <table>
       <thead>
        <tr>
            <th>医生编号</th>
            <th>医生姓名</th>
            <th>入院时间</th>
            <th>所属科室</th>
            <th>操作</th>
        </tr>
        </thead>
        	<!--doctorList的类型为PageInfo类型-->
    	     <c:forEach items="${doctorList.list }" var="d" varStatus="status">
    			<tr>
    				<td style="vertical-align: middle;"><input type="checkbox"
    					name="check" value="1"></td>
    				<td>${d.id }</td>
    				<td>${d.name }</td>
    				<td><fmt:formatDate value="${d.time }" pattern="yyyy年MM月dd日"/>  </td>
    				<td>${d.seccoXuan.seccoName }</td>
    				<td><a href="doctor/toEditPage?id=${d.id }&pageNum=${doctorList.pageNum}">更改</a>&nbsp;&nbsp;&nbsp;
    				<a href="doctor/detail?id=${d.id }&pageNum=${doctorList.pageNum}"	>详情</a></td>
    			</tr>
    		</c:forEach>
      </table>
      
     <table>
    		<tr>
    			<th colspan="5">
    				<div class="inline pull-right page">
    					共${doctorList.total }条记录 ${doctorList.pageNum }/${doctorList.pages } 页
    					<c:if test="${doctorList.isFirstPage }">
    						<a href="javascript:void()" aria-label="Previous"> <span
    							aria-hidden="true">&laquo;</span>
    						</a>
    					</c:if>
    					<!--如果不是首页就可以往前跳一页-->
    					<c:if test="${!doctorList.isFirstPage }">
    						<a href='${pageContext.request.contextPath}/doctor/forward.action?pageNum=${doctorList.pageNum - 1 }'>&laquo;</a>
    					</c:if>
    					<c:forEach items="${doctorList.navigatepageNums }" var="n">
    						<!-- 判断是否是当前页,是导航页就是选中状态 -->
    						<c:if test="${n==doctorList.pageNum }">
    							<a class="product-ym_bg" href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${n }">${n }</a>
    						</c:if>
    						<!-- 判断是否是当前页,是导航页就是非选中状态 -->
    						<c:if test="${n!=doctorList.pageNum}">
    							<a class="product-ym_bg" href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${n }">${n }</a>
    						</c:if>
    					</c:forEach>
    					<!--如果是尾页-->
    					<c:if test="${doctorList.isLastPage }">
    
    						<a href="javascript:void()" aria-label="Next"> <span
    							aria-hidden="true">&raquo;</span>
    						</a>
    
    					</c:if>
    					<!-- 如果不是最后一页,是就可以点击下一页 -->
    					<c:if test="${!doctorList.isLastPage }">
    
    						<a class="product-ym_xyy"
    							href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${doctorList.pageNum + 1 }"
    							aria-label="Next"> <span aria-hidden="true">&raquo;</span>
    						</a>
    
    					</c:if>
    				</div>
    
    				<div>
    					<button type="button" class="btn btn-success" onclick="addDoctor()">添加医生</button>
    					&nbsp;&nbsp;&nbsp;
    					<button type="button" class="btn btn-success" id="delPro"
    						onClick="delAll();">删除选中</button>
    				</div>
    			</th>
    		</tr>
    	</table>
    
  6. 后端

    @RequestMapping(value = "/forward.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
    public String forward(Model model, @RequestParam(defaultValue = "1")int pageNum,@RequestParam(defaultValue = "2")int pageSize){
        PageHelper.startPage(pageNum,pageSize);//该语句后面紧挨着的查询语句就会分页
        List<Doctor> doctors = doctorService.find();
        PageInfo<Doctor> doctorList = new PageInfo<Doctor>(doctors);
        model.addAttribute("doctorList",doctorList);
        return "/doctor/index";
    }
    

🍓Spring请求转发(forward)和重定向(redirect)

	//请求转发
	return "forward:/itemEdit.action";

	//重定向
	return "redirect:/itemEdit.action?id="+item.getId();

区别:

  1. 地址显示不同,重定向显示跳转后的页面的地址,请求转发显示的是请求页面的地址(原来的地址)
  2. 请求转发客户端请求次数只有一次,因为是服务器内部帮客户端执行了后续的转发到第二个接口的工作,重定向请求次数是两次,客户端第一次请求后,接口会引导客户端去第二次请求另外一个接口(所以这也是为什么请求转发地址不变,重定向地址改变,并且不能共享请求参数,需要执行两次,且可以跳转到本项目以外的地址的原因)
  3. 请求转发只能跳转到自己项目的资源路径,重定向可以跳转到任意路径,不是自己的工程也可以跳
  4. 请求转发效率高,因为只执行一次请求,重定向效率低,执行两次请求
  5. 请求转发可以使用上一次的request对象,重定向后续的请求,没法使用上一次的 request 存储的数据,或者没法使用上一次的 request 对象,因为这是两次不同的请求

注意:
请求转发虽然效率高,但是存在风险,因为客户端地址不变,刷新会造成接口的重复请求,例如写操作,删除操作,修改操作最好使用重定向到列表

🍓拓展(JDBCTemplate)

在一些公司还会使用Spring自带的JDBCTemplate代替mybatis,这里我引用一篇较好的博客来理解JDBCTemplate的用法
JDBCTemplate的用法

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值