Java教程

SSM整合---狂神说Java学习笔记

本文主要是介绍SSM整合---狂神说Java学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

SSM 整合

哔哩哔哩狂神说Java学习网址
文章只为分享学习经验和自己复习用,学习还是该去查看正规视频网站和官方文档才更有效

文章目录

  • SSM 整合
    • 一、环境要求
    • 二、数据库环境
    • 三、基本环境搭建
    • 四、Mybatis层编写
    • 五、Spring层编写
    • 六、Spring MVC层编写
    • 七、Controller 和 视图层编写
      • 1、先简单编写,测试一下后端底层代码是否正确
      • 2、开始正是编写前端
      • 3、添加书籍
      • 4、修改、删除书籍
    • 八、项目结构图
    • 九、全部代码
    • 十、小结及展望
    • 十一、报错或Eclipse使用问题
      • 1、eclipse-maven-web-pom第一条报错
      • 2、.properties文件中文乱码问题
      • 3、eclipes的target中class被隐藏
  • 新增搜索功能
  • Ajax
    • 一、简介
    • 二、伪造Ajax
    • 三、jQuery.ajax
    • 四、Ajax异步加载数据
    • 五、Ajax验证用户名体验
    • 问题解决
      • 1、List 返回报错
  • 拦截器
    • 一、概述
    • 二、自定义拦截器
    • 三、登录判断验证
  • 文件上传和下载
    • 一、文件上传
    • 二、文件下载
  • SSM整合回顾

使用SSM框架制作一个书籍查询项目

项目的简单核心中轴线

在这里插入图片描述

我使用的eclips开发工具,和主播的操作可能存在不同

一、环境要求

环境:

  • IDEA
  • MySQL 5.7.19
  • Tomcat 9
  • Maven 3.6

要求:

  • 需要熟练掌握MySQL数据库,Spring,JavaWeb及MyBatis知识,简单的前端知识;

二、数据库环境

创建一个存放书籍数据的数据库表

CREATE DATABASE `ssmbuild`;
 
USE `ssmbuild`;
 
DROP TABLE IF EXISTS `books`;
 
CREATE TABLE `books` (
  `bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
  `bookName` VARCHAR(100) NOT NULL COMMENT '书名',
  `bookCounts` INT(11) NOT NULL COMMENT '数量',
  `detail` VARCHAR(200) NOT NULL COMMENT '描述',
  KEY `bookID` (`bookID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
 
INSERT  INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES 
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');

程序员90%的业务就是CRUD(增删改查)

三、基本环境搭建

Maven基本项目里至少要完成两件事情,依赖和静态资源导出问题。

依赖:

  • junit
  • 数据库驱动
  • 连接池
  • servlet
  • jsp
  • mybatis
  • mabattis-spring
  • spring

1、新建一Maven项目!ssmbuild , 添加web的支持

eclipse,创建Maven-web项目

2、导入相关的pom依赖!

<dependencies>
    <!--Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- 数据库连接池 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>
 
    <!--Servlet - JSP -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
 
    <!--Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
 
    <!--Spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>

3、Maven资源过滤设置

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

4、建立基本结构和配置框架!

  • com.kuang.pojo (数据对象原型)

  • com.kuang.dao (连接数据层)

  • com.kuang.service (业务逻辑层)

  • com.kuang.controller (接收前段业务层)

  • mybatis-config.xml(mybatis配置文件)

    <?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>
     
    </configuration>
    
  • applicationContext.xml(spring配置文件)

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

四、Mybatis层编写

1、数据库配置文件 database.properties

jdbc.driver=com.mysql.jdbc.Driver
# 如果使用的是MySQL8.0+, 需要增加一个时区的配置;&serverTimezone=Asia/Shanghai
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

这里发现eclipse的.properties文件中文出现乱码问题解决方法—11.1

2、IDEA关联数据库

(我使用的是eclipse工具,没找到关联数据库的方法,以后再研究)

3、编写MyBatis的核心配置文件

mybatis-config.xml

<?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>
    
	<!-- 配置数据源,交给Spring去做 -->
	<typeAliases>
		<package name="com.kuang.pojo"/>
	</typeAliases>
	
	<mappers>
		<mapper resource="com/kuang/dao/BookMapper.xml"/>
	</mappers>
 
</configuration>

老师视频中使用的是:<mapper class="com.kuang.dao.BookMapper.xml"/>

但是我使用class搜索不到,所以使用resource

在这里插入图片描述

4、编写数据库对应的实体类 com.kuang.pojo.Books

lombok依赖

但是我使用eclips工具,lombok直接用依赖无法使用,以后再研究

<!-- Lombok -->
	<dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombpk</artifactId>
        <version>1.16.10</version>
    </dependency>
package com.kuang.pojo;
 
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {
    
    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
    
}

5、编写Dao层的 Mapper接口!

package com.kuang.dao;
 
import com.kuang.pojo.Books;
import java.util.List;
 
public interface BookMapper {
 
    //增加一个Book
    int addBook(Books book);
 
    //根据id删除一个Book
    int deleteBookById(@Param("bookId") int id);
 
    //更新Book
    int updateBook(Books books);
 
    //根据id查询,返回一个Book
    Books queryBookById(@Param("bookId") int id);
 
    //查询全部Book,返回list集合
    List<Books> queryAllBook();
 
}

6、编写接口对应的 Mapper.xml 文件。需要导入MyBatis的包;

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.BookMapper">
    
	<insert id="addBook" parameterType="Books">
		insert into ssmbuild.books (bookName,bookCounts,detail) 
		values(#{bookName},#{bookCounts},#{detail});
	</insert>
	
	<delete id="deleteBookById" parameterType="int">
		delete from ssmbuild.books 
		where bookID=#{bookId};
	</delete>
	
	<update id="updateBook" parameterType="Books">
		update ssmbuild.books
		set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail} 
		where bookID=#{bookId};
	</update>
	
	<select id="queryBookById" resultType="Books">
		select * from ssmbuild.books 
		where bookID=#{bookId};
	</select>
	
	<select id="queryAllBook" resultType="Books">
		select * from ssmbuild.books;
	</select>
	
	<!-- 输入完第一件事就是核心配置文件注册 -->
	
	
</mapper>

7、编写Service业务层的接口和实现类

接口

package com.kuang.service;

import java.util.List;

import com.kuang.pojo.Books;

public interface BookService {
	
    //增加一个Book
    int addBook(Books book);
 
    //根据id删除一个Book
    int deleteBookById(int id);
 
    //更新Book
    int updateBook(Books books);
 
    //根据id查询,返回一个Book
    Books queryBookById(int id);
 
    //查询全部Book,返回list集合
    List<Books> queryAllBook();	

}

实现类

package com.kuang.service;

import java.util.List;

import com.kuang.dao.BookMapper;
import com.kuang.pojo.Books;

public class BookServiceImpl implements BookService {
	//service业务层调dao层:组合dao层
	
	private BookMapper bookMapper;
	
	public void setBookMapper(BookMapper bookMapper) {
		this.bookMapper = bookMapper;
	}

	@Override
	public int addBook(Books book) {
		return bookMapper.addBook(book);
	}

	@Override
	public int deleteBookById(int id) {
		return bookMapper.deleteBookById(id);
	}

	@Override
	public int updateBook(Books books) {
		return bookMapper.updateBook(books);
	}

	@Override
	public Books queryBookById(int id) {
		return bookMapper.queryBookById(id);
	}

	@Override
	public List<Books> queryAllBook() {
		return bookMapper.queryAllBook();
	}

}

Mybatis层核心就是在写底层,建数据库、pojo数据实体类、dao层和service层的简单动作

五、Spring层编写

1、配置Spring整合MyBatis,我们这里数据源使用c3p0连接池;

2、我们去编写Spring整合Mybatis的相关的配置文件;spring-dao.xml

数据库连接池有很多种

  • dbcp:半自动化操作,不能自动连接
  • c3p0:自动化操作(自动化的加载配置文件,并且可以自动设置到对象中)
  • druid
  • hikari
<?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"   
           
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
        
        <!-- 1.关联数据库配置文件 -->
    	<context:property-placeholder location="classpath:database.properties"/>        
        
        <!-- 2.数据库连接池 -->
   		<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        
        <!-- c3p0连接池的私有属性 -->
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <!-- 关闭连接后不自动commit -->
        <property name="autoCommitOnClose" value="false"/>
        <!-- 获取连接超时时间 -->
        <property name="checkoutTimeout" value="10000"/>
        <!-- 当获取连接失败重试次数 -->
        <property name="acquireRetryAttempts" value="2"/>
 		
   		</bean>    

	    <!-- 3.配置SqlSessionFactory对象 -->
	    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	        <!-- 注入数据库连接池 -->
	        <property name="dataSource" ref="dataSource"/>
	        <!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
	        <property name="configLocation" value="classpath:mybatis-config.xml"/>
	    </bean>
	    
	    <!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
	    <!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html-->
	    
	    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	        <!-- 注入sqlSessionFactory -->
	        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
	        <!-- 给出需要扫描Dao接口包 -->
	        <property name="basePackage" value="com.kuang.dao"/>
	    </bean>

 
</beans>

3、Spring整合service层

spring-service.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 可以通过import关联
    	<import resource="classpath:spring-dao.xml"/>
    	也可以在applicationContext.xml中全部import关联
     -->
 
    <!-- 1.扫描service的包 -->
    <context:component-scan base-package="com.kuang.service" />
 
    <!-- 2.将我们的所有业务类,BookServiceImpl注入到spring,可以通过配置,或者注解实现-->
    <bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl">
        <property name="bookMapper" ref="bookMapper"/>
    </bean>
    <!-- 3.配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据库连接池数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 再有的话就是4.aop事务支撑 -->
</beans>

也可以通过注解注入到spring

在这里插入图片描述

applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <import resource="classpath:spring-dao.xml"/>
        <import resource="classpath:spring-service.xml"/>
 
</beans>

Spring层搞定!再次理解一下,Spring就是一个大杂烩,一个容器

六、Spring MVC层编写

1、web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" 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">

	<!-- DispatchServlet -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
            <!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!--> 
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- 乱码过滤 -->
	<filter>
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--Session过期时间-->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>
 
</web-app>

2、spring-mvc.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.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
        
	<!-- 1.注解驱动 -->
	<mvc:annotation-driven/>
	<!-- 2.静态资源过滤 -->
	<mvc:default-servlet-handler/>
	<!-- 3.扫描包:controller -->
	<context:component-scan base-package="com.kuang.controller"/>
	<!-- 4.视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />      
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

3、Spring配置整合文件,applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <import resource="classpath:spring-dao.xml"/>
        <import resource="classpath:spring-service.xml"/>
    	<import resource="classpath:spring-mvc.xml"/>
 
</beans>

两种获取方法都可以使用

<import resource="spring-dao.xml"/>

<import resource="spring-service.xml"/>

<import resource="spring-mvc.xml"/>

这些底层以后大部分业务都可以使用,最好保存下来

配置文件,暂时结束!Controller 和 视图层编写

七、Controller 和 视图层编写

1、先简单编写,测试一下后端底层代码是否正确

1.1、com.kuang.controller.BookController 类编写 , 方法一:查询全部书籍

package com.kuang.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.kuang.pojo.Books;
import com.kuang.service.BookService;

@Controller
@RequestMapping("/book")
public class BookController {
	//Controller 调 service层
	@Autowired
	@Qualifier("BookServiceImpl")
	private BookService bookService;
	
	//查询全部的书籍,并且返回到一个书籍展示页面
	@RequestMapping("/allBook")
	public String list(Model model) {
		List<Books> list = bookService.queryAllBook();
		model.addAttribute("list", list);
		return "allbook";
	}
	
}

1.2、编写首页 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h3>
	<a href="${pageContext.request.contextPath}/book/allBook">进入书籍页面</a>
</h3>
</body>
</html>

1.3、书籍列表页面 allbook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>书籍展示</title>
</head>
<body>
<h1>书籍展示</h1>
</body>
</html>

第一次底层测试,发现报错

报错:问题 bean 不存在

分析步骤:

  1. 查看这个bean注入是否成功

  2. Junit单元测试,看我们的代码是否能够查询出来结果

    public class MyTest {
    	@Test
    	public void test() {
    		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    		BookServiceImpl bookServiceImpl = (BookServiceImpl) context.getBean("BookServiceImpl");
    		for (Books books : bookServiceImpl.queryAllBook()) {
    			System.out.println(books);
    		}
    	}
    }
    

    通过查询可以获得结果,底层代码肯定没问题。

  3. 肯定是Spring出了问题

  4. SpringMVC,整合的时候没电泳到我们的sevice层的bean

    • applicationContext.xml 有没有注入bean(已经整合)

    • web.xml中,也绑定过配置文件

      发现问题,我们配置的是Spring-mvc.xml,这里面确实没有 service bean,所有报空指针异常
      在这里插入图片描述

      该为汇总的applicationContext.xml,就可以正常运行。

2、开始正是编写前端

2.1、美化首页 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
<style>
	a{
		text-decoration:none;
		color:black;
		font-size:18px;
	}
	h3{
		width:180px;
		height:38px;
		margin:100px auto;
		text-align:center;
		line-height:38px;
		background:deepskyblue;
		border-radius:5px;
	}
</style>
</head>
<body>

<h3>
    <a href="${pageContext.request.contextPath}/book/allBook">点击进入列表页</a>
</h3>

</body>
</html>

2.2、美化书籍展示界面 allBook.jsp

使用BootStrap美化界面,官网:https://www.bootcss.com/

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>书籍展示</title>

<%-- BootStrap 美化界面 --%>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>
<%-- container一种格式边框 --%>
<div class="container">
	<%-- 清除浮动 --%>
	<div class="row clearfix">
		<%-- 分割,将屏幕横向分成12份,md屏幕大小,12占满全部12份 --%>
		<div class="col-md-12 column">
			<%-- 头部 --%>
			<div class="page-header">
				<%-- small标签 --%>
				<h1>
					<small>书籍列表 ———— 显示所有书籍</small>
				</h1>
			</div>
		</div>
	</div>
	

	
	<div class="row clearfix">
		<div class="col-md-12 column">
			<table class="table table-hover table-striped">
				<thead>
					<tr>
						<th>书籍编号</th>
						<th>书籍名称</th>
						<th>书籍数量</th>
						<th>书籍详情</th>
					</tr>
				</thead>
				<%-- 书籍从数据库中查询出来,从这个list中遍历出来:forEach(注意抬头引用) --%>
				<tbody>
				<%-- 获取数据 --%>
					<c:forEach var="book" items="${list}">
						<tr>
							<td>${book.bookID}</td>
							<td>${book.bookName}</td>
							<td>${book.bookCounts}</td>
							<td>${book.detail}</td>
						</tr>
					</c:forEach>
				</tbody>
			</table>
		
		</div>
	</div>

</div>
</body>
</html>

3、添加书籍

3.1、allBook.jsp 书籍展示界面添加功能: 新增书籍

	<div class="row clearfix">
		<div class="col-md-4 column">
			<%-- toAddBook --%>
			<a href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
		</div>
	</div>

3.2、BookController 类编写方法:添加书籍

    //跳转到增加书籍的页面
    @RequestMapping("/toAddBook")
    public String toAddPaper() {
    	return "addBook";
    }
    
    //增加书籍的请求
    @RequestMapping("/addBook")
    public String addPaper(Books books) {
    	System.out.println("addBook=>"+books);
    	bookService.addBook(books);
    	return "redirect:/book/allBook";//重定向
    }

3.3、添加书籍页面 addBook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>增加书籍</title>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
	<div class="row clearfix">
		<div class="col-md-12 column">
			<div class="page-header">
				<h1>
					<small>新增书籍</small>
				</h1>
			</div>
		</div>
	</div>
	
    <form action="${pageContext.request.contextPath}/book/addBook" method="post">
        书籍名称:<input type="text" name="bookName" required><br><br><br>
        书籍数量:<input type="text" name="bookCounts" required><br><br><br>
        书籍详情:<input type="text" name="detail" required><br><br><br>
        <input type="submit" value="添加">
    </form>
</div>

</body>
</html>

4、修改、删除书籍

4.1、allbook.jsp 添加功能: 修改、删除

<td>
<%-- 发送修改消息,并且发现修改对象的id,让修改的时候可以看到对象值 --%>
<a href="${pageContext.request.contextPath}/book/toUpdate?id=${book.bookID}">修改</a>
|
<a href="${pageContext.request.contextPath}/book/deleteBook/${book.bookID}">删除</a>
</td>

(老师使用&nbsp;进行空格,但是我这程序只读取了字符串并未转换为空格,所以我没使用)

4.2、BookController 类编写方法三:修改书籍

    //跳转到修改页面
    @RequestMapping("/toUpdate")
    	//获得对象的id,方便修改页面显示出对象的值。并使用model携带
    public String toUpdatePaper(int id,Model model) {
    	Books books = bookService.queryBookById(id);
    	model.addAttribute("QBook",books);
    	return "updateBook";
    }
    //修改书籍的请求
    @RequestMapping("/updateBook")
    public String UpdateBook(Books books) {
    	System.out.println("UpdateBook=>"+books);
    	bookService.updateBook(books);
    	return "redirect:/book/allBook";//重定向
    }

4.3、修改书籍页面 updateBook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>修改书籍</title>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
	<div class="row clearfix">
		<div class="col-md-12 column">
			<div class="page-header">
				<h1>
					<small>修改书籍</small>
				</h1>
			</div>
		</div>
	</div>
	<%-- 原来在没有bookID时,运行出现问题:提交修改的SQL请求时出现问题,提交成功,但是内容没有修改 --%>
	<%-- 初次考虑是提交事务问题,配置完毕后发现依旧失败 --%>
	<%-- 看一下SQL语句,能否执行成功:SQL执行失败,修改未完成,发现会ID默认提交为0,和实际参数不符,数据库也没有这个参数 --%>
	<%-- 修改:增加bookID语句,可以使用前段传递隐藏域 --%>
	<%-- <input type="hidden" name="bookID" value="${QBook.bookID}"> --%>
	<%-- 我觉得显示ID更合理,readonly不可修改的内容,并染色 --%>
    <form action="${pageContext.request.contextPath}/book/updateBook" method="post">
        ID:<input type="text" name="bookID" value="${QBook.bookID}" style="background:#FFFF00" readonly><br><br><br>
        书籍名称:<input type="text" name="bookName" value="${QBook.bookName}" required><br><br><br>
        书籍数量:<input type="text" name="bookCounts" value="${QBook.bookCounts}" required><br><br><br>
        书籍详情:<input type="text" name="detail" value="${QBook.detail}" required><br><br><br>
        <input type="submit" value="修改">
    </form>
</div>

</body>
</html>

修改功能程序出现的问题:

  • 开始刚添加时由于ID不能修改,所以并未打算传输bookID,但是运行时出现了问题:提交修改的SQL请求时出现问题,提交成功,但是内容没有修改

  • 初次考虑是提交事务问题,配置完毕后发现依旧失败

    横切事务:

    事务jar包

    <dependency>
    	<groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
    	<version>1.8.13</version>
    </dependency>
    

    横切:

    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaciton-manager="transactionManager">
        <tx:attributes>
        	<tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 配置事务切入 -->
    <aop:config>
    	<aop:pointcut id="txPointCut" expression="execution(* com.kuang.dao.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
    
  • 看一下SQL语句,能否执行成功:SQL执行失败,修改未完成,发现会ID默认提交为0,和实际参数不符,数据库也没有这个参数

  • 修改:增加bookID语句,可以使用前段传递隐藏域

4.4、BookController - 类编写方法四:删除书籍

    //删除书籍
    	//提交的id会转换为bookId,并且解析为int类型传到下面
    @RequestMapping("/deleteBook/{bookId}")
    public String deleteBook(@PathVariable("bookId") int id) {
    	bookService.deleteBookById(id);
    	return "redirect:/book/allBook";
    }

八、项目结构图

在这里插入图片描述
在这里插入图片描述

九、全部代码

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.kuang</groupId>
  <artifactId>ssmbuild03</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
    <!--Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- 数据库连接池 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>
 
    <!--Servlet - JSP -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
 
    <!--Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
 
    <!--Spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

</project>

src/mian/java

com.kuang.controller.BookController.java

package com.kuang.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.kuang.pojo.Books;
import com.kuang.service.BookService;

@Controller
@RequestMapping("/book")

public class BookController {

	 
    @Autowired
    @Qualifier("BookServiceImpl")
    private BookService bookService;
 
    @RequestMapping("/allBook")
    public String list(Model model) {
        List<Books> list = bookService.queryAllBook();
        model.addAttribute("list", list);
        return "allbook";
    }
    
    //跳转到增加书籍的页面
    @RequestMapping("/toAddBook")
    public String toAddPaper() {
    	return "addBook";
    }
    
    //增加书籍的请求
    @RequestMapping("/addBook")
    public String addPaper(Books books) {
    	System.out.println("addBook=>"+books);
    	bookService.addBook(books);
    	return "redirect:/book/allBook";//重定向
    }
    
    //跳转到修改页面
    @RequestMapping("/toUpdate")
    	//获得对象的id,方便修改页面显示出对象的值。并使用model携带
    public String toUpdatePaper(int id,Model model) {
    	Books books = bookService.queryBookById(id);
    	model.addAttribute("QBook",books);
    	return "updateBook";
    }
    //修改书籍的请求
    @RequestMapping("/updateBook")
    public String UpdateBook(Books books) {
    	System.out.println("UpdateBook=>"+books);
    	bookService.updateBook(books);
    	return "redirect:/book/allBook";//重定向
    }
    
    //删除书籍
    	//提交的id会转换为bookId,并且解析为int类型传到下面
    @RequestMapping("/deleteBook/{bookId}")
    public String deleteBook(@PathVariable("bookId") int id) {
    	bookService.deleteBookById(id);
    	return "redirect:/book/allBook";
    }
}

com.kuang.dao.BookMapper.java

package com.kuang.dao;

import java.util.List;

import com.kuang.pojo.Books;

public interface BookMapper {


    //增加一个Book
    int addBook(Books book);
 
    //根据id删除一个Book
    int deleteBookById(int id);
 
    //更新Book
    int updateBook(Books books);
 
    //根据id查询,返回一个Book
    Books queryBookById(int id);
 
    //查询全部Book,返回list集合
    List<Books> queryAllBook();

}

com.kuang.dao.BookMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.kuang.dao.BookMapper">
 
    <!--增加一个Book-->
    <insert id="addBook" parameterType="Books">
        insert into ssmbuild.books(bookName,bookCounts,detail)
        values (#{bookName}, #{bookCounts}, #{detail})
    </insert>
 
    <!--根据id删除一个Book-->
    <delete id="deleteBookById" parameterType="int">
        delete from ssmbuild.books where bookID=#{bookID}
    </delete>
 
    <!--更新Book-->
    <update id="updateBook" parameterType="Books">
        update ssmbuild.books
        set bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail}
        where bookID = #{bookID}
    </update>
 
    <!--根据id查询,返回一个Book-->
    <select id="queryBookById" resultType="Books">
        select * from ssmbuild.books
        where bookID = #{bookID}
    </select>
 
    <!--查询全部Book-->
    <select id="queryAllBook" resultType="Books">
        SELECT * from ssmbuild.books
    </select>
 
</mapper>

com.kuang.pojo.Books.java

package com.kuang.pojo;

public class Books {


    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
	public Books() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Books(int bookID, String bookName, int bookCounts, String detail) {
		super();
		this.bookID = bookID;
		this.bookName = bookName;
		this.bookCounts = bookCounts;
		this.detail = detail;
	}
	public int getBookID() {
		return bookID;
	}
	public void setBookID(int bookID) {
		this.bookID = bookID;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public int getBookCounts() {
		return bookCounts;
	}
	public void setBookCounts(int bookCounts) {
		this.bookCounts = bookCounts;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}
	@Override
	public String toString() {
		return "Books [bookID=" + bookID + ", bookName=" + bookName + ", bookCounts=" + bookCounts + ", detail="
				+ detail + "]";
	}	
}

com.kuang.service.BookService.java

package com.kuang.service;

import java.util.List;

import com.kuang.pojo.Books;

public interface BookService {


    //增加一个Book
    int addBook(Books book);
    //根据id删除一个Book
    int deleteBookById(int id);
    //更新Book
    int updateBook(Books books);
    //根据id查询,返回一个Book
    Books queryBookById(int id);
    //查询全部Book,返回list集合
    List<Books> queryAllBook();

}

com.kuang.service.BookServiceImpl.java

package com.kuang.service;

import java.util.List;

import com.kuang.dao.BookMapper;
import com.kuang.pojo.Books;

public class BookServiceImpl implements BookService {

	 
    //调用dao层的操作,设置一个set接口,方便Spring管理
    private BookMapper bookMapper;
 
    public void setBookMapper(BookMapper bookMapper) {
        this.bookMapper = bookMapper;
    }
    
    public int addBook(Books book) {
        return bookMapper.addBook(book);
    }
    
    public int deleteBookById(int id) {
        return bookMapper.deleteBookById(id);
    }
    
    public int updateBook(Books books) {
        return bookMapper.updateBook(books);
    }
    
    public Books queryBookById(int id) {
        return bookMapper.queryBookById(id);
    }
    
    public List<Books> queryAllBook() {
        return bookMapper.queryAllBook();
    }
}

src/mian/resources

applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        
    <import resource="spring-dao.xml"/>
    <import resource="spring-service.xml"/>
    <import resource="spring-mvc.xml"/>
        
 
</beans>

database.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

mybatis-config.xml

<?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.kuang.pojo"/>
    </typeAliases>
    

    <mappers>
        <mapper resource="com/kuang/dao/BookMapper.xml"/>
    </mappers>
 
</configuration>

spring-dao.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
 
    <!-- 配置整合mybatis -->
    <!-- 1.关联数据库文件 -->
    <context:property-placeholder location="classpath:database.properties"/>
 
    <!-- 2.数据库连接池 -->
    <!--数据库连接池
        dbcp  半自动化操作  不能自动连接
        c3p0  自动化操作(自动的加载配置文件 并且设置到对象里面)
    -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 配置连接池属性 -->
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- c3p0连接池的私有属性 -->
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <!-- 关闭连接后不自动commit -->
        <property name="autoCommitOnClose" value="false"/>
        <!-- 获取连接超时时间 -->
        <property name="checkoutTimeout" value="10000"/>
        <!-- 当获取连接失败重试次数 -->
        <property name="acquireRetryAttempts" value="2"/>
    </bean>
    <!-- 3.配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
    <!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入sqlSessionFactory -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 给出需要扫描Dao接口包 -->
        <property name="basePackage" value="com.kuang.dao"/>
    </bean>
</beans>

spring-mvc.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">
 
    <!-- 配置SpringMVC -->
    <!-- 1.开启SpringMVC注解驱动 -->
    <mvc:annotation-driven />
    <!-- 2.静态资源默认servlet配置-->
    <mvc:default-servlet-handler/>
 
    <!-- 3.配置jsp 显示ViewResolver视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- 4.扫描web相关的bean -->
    <context:component-scan base-package="com.kuang.controller" />
</beans>

spring-service.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
 
    <!-- 扫描service相关的bean -->
    <context:component-scan base-package="com.kuang.service" />
 
    <!--BookServiceImpl注入到IOC容器中-->
    <bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl">
        <property name="bookMapper" ref="bookMapper"/>
    </bean>
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

前端

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" 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">
<!--DispatcherServlet-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!-->  
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!--encodingFilter-->
    <filter>
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!--Session过期时间-->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>

</web-app>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>首页</title>
    <style type="text/css">
        a {
            text-decoration: none;
            color: black;
            font-size: 18px;
        }
        h3 {
            width: 180px;
            height: 38px;
            margin: 100px auto;
            text-align: center;
            line-height: 38px;
            background: deepskyblue;
            border-radius: 4px;
        }
    </style>
</head>
<body>
 
<h3>
    <a href="${pageContext.request.contextPath}/book/allBook">点击进入列表页</a>
</h3>
</body>

</html>

addBook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>增加书籍</title>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
	<div class="row clearfix">
		<div class="col-md-12 column">
			<div class="page-header">
				<h1>
					<small>新增书籍</small>
				</h1>
			</div>
		</div>
	</div>
	
    <form action="${pageContext.request.contextPath}/book/addBook" method="post">
        书籍名称:<input type="text" name="bookName" required><br><br><br>
        书籍数量:<input type="text" name="bookCounts" required><br><br><br>
        书籍详情:<input type="text" name="detail" required><br><br><br>
        <input type="submit" value="添加">
    </form>
</div>

</body>
</html>

allbook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>书籍展示</title>

<%-- BootStrap 美化界面 --%>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>
<%-- container一种格式边框 --%>
<div class="container">
	<%-- 清除浮动 --%>
	<div class="row clearfix">
		<%-- 分割,将屏幕横向分成12份,md屏幕大小,12占满全部12份 --%>
		<div class="col-md-12 column">
			<%-- 头部 --%>
			<div class="page-header">
				<%-- small标签 --%>
				<h1>
					<small>书籍列表 ———— 显示所有书籍</small>
				</h1>
			</div>
		</div>
	</div>
	
	<div class="row clearfix">
		<div class="col-md-4 column">
			<%-- toAddBook --%>
			<a href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
		</div>
	</div>
	
	<div class="row clearfix">
		<div class="col-md-12 column">
			<table class="table table-hover table-striped">
				<thead>
					<tr>
						<th>书籍编号</th>
						<th>书籍名称</th>
						<th>书籍数量</th>
						<th>书籍详情</th>
						<th>操作</th>
					</tr>
				</thead>
				<%-- 书籍从数据库中查询出来,从这个list中遍历出来:forEach(注意抬头引用) --%>
				<tbody>
				<%-- 获取数据 --%>
					<c:forEach var="book" items="${list}">
						<tr>
							<td>${book.bookID}</td>
							<td>${book.bookName}</td>
							<td>${book.bookCounts}</td>
							<td>${book.detail}</td>
							<td>
								<%-- 发送修改消息,并且发现修改对象的id,让修改的时候可以看到对象值 --%>
								<a href="${pageContext.request.contextPath}/book/toUpdate?id=${book.bookID}">修改</a>
								 |
								<a href="${pageContext.request.contextPath}/book/deleteBook/${book.bookID}">删除</a>
								
							</td>
						</tr>
					</c:forEach>
				</tbody>
			</table>
		
		</div>
	</div>

</div>
</body>
</html>

updateBook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>修改书籍</title>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
	<div class="row clearfix">
		<div class="col-md-12 column">
			<div class="page-header">
				<h1>
					<small>修改书籍</small>
				</h1>
			</div>
		</div>
	</div>
	<%-- 原来在没有bookID时,运行出现问题:提交修改的SQL请求时出现问题,提交成功,但是内容没有修改 --%>
	<%-- 初次考虑是提交事务问题,配置完毕后发现依旧失败 --%>
	<%-- 看一下SQL语句,能否执行成功:SQL执行失败,修改未完成,发现会ID默认提交为0,和实际参数不符,数据库也没有这个参数 --%>
	<%-- 修改:增加bookID语句,可以使用前段传递隐藏域 --%>
	<%-- <input type="hidden" name="bookID" value="${QBook.bookID}"> --%>
	<%-- 我觉得显示ID更合理,readonly不可修改的内容,并染色 --%>
    <form action="${pageContext.request.contextPath}/book/updateBook" method="post">
        ID:<input type="text" name="bookID" value="${QBook.bookID}" style="background:#FFFF00" readonly><br><br><br>
        书籍名称:<input type="text" name="bookName" value="${QBook.bookName}" required><br><br><br>
        书籍数量:<input type="text" name="bookCounts" value="${QBook.bookCounts}" required><br><br><br>
        书籍详情:<input type="text" name="detail" value="${QBook.detail}" required><br><br><br>
        <input type="submit" value="修改">
    </form>
</div>

</body>
</html>

十、小结及展望

这个是同学们的第一个SSM整合案例,一定要烂熟于心!

SSM框架的重要程度是不言而喻的,学到这里,大家已经可以进行基本网站的单独开发。但是这只是增删改查的基本操作。可以说学到这里,大家才算是真正的步入了后台开发的门。也就是能找一个后台相关工作的底线。

或许很多人,工作就做这些事情,但是对于个人的提高来说,还远远不够!

我们后面还要学习一些 SpringMVC 的知识!

  • Ajax 和 Json
  • 文件上传和下载
  • 拦截器

前路漫漫,认真坚持最重要

十一、报错或Eclipse使用问题

1、eclipse-maven-web-pom第一条报错

找不到project声明

Multiple annotations found at this line: schema_reference.4: Failed to read schema document 'https://maven.apache.org/xsd/maven-4.0.0.xsd', because could not find the document; the document could not be read; 3) the root element of the document is not <xsd:schema>. cvc-elt.1.a: Cannot find the declaration of element 'project'.

错误信息: 开发环境 eclipse ,maven项目,pom.xml第一行 <project …标签处一直报这个错误:cvc-elt.1: Cannot find the declaration of element ‘project’.

解决方法: 右键maven项目, maven——>update project ,记得勾选上 force update of snapshots/release

解决方法网址

2、.properties文件中文乱码问题

发现eclipse的.properties文件中文出现乱码问题

第一步:windows–>properties–>General–>Content Types–>text(如下图)

在这里插入图片描述

解决方法网址

3、eclipes的target中class被隐藏

取消隐藏方法

在这里插入图片描述
在这里插入图片描述

解决方法网址

  1. 4、解决eclipse启动tomcat报错

解决eclipse启动tomcat报错:Could not load the Tomcat server configuration at \Servers\Tomcat v6.0 Server at localhost-config. The Servers project is closed.

双击Servers即可

在这里插入图片描述

解决方法网址

新增搜索功能

在原代码上新增搜索功能

  • 正常一个用户的浏览顺序是:前端 —> Controller层 —> service层 —> dao层 —> 数据库
  • 但编程应该从:数据库 —> dao层 —> service层 —> Controller层 —> 前端
  • 如果没有整体思路也可以从前端开始写,但是步骤会比较多。

再原有的代码上进行补全:

dao层

/ssmbuild03/src/main/java/com/kuang/dao/BookMapper.java

    //按名字搜索
    Books queryBookName(@Param("bookName") String bookName);

/ssmbuild03/src/main/java/com/kuang/dao/BookMapper.xml

 	<!--按名字搜索-->
    <select id="queryBookName" resultType="Books">
        select * from ssmbuild.books
        where bookName = #{bookName}
    </select>

service层

/ssmbuild03/src/main/java/com/kuang/service/BookService.java

    //按名字搜索
    Books queryBookName(String bookName);

/ssmbuild03/src/main/java/com/kuang/service/BookServiceImpl.java

	@Override
	public Books queryBookName(String bookName) {	
		return bookMapper.queryBookName(bookName);
	}

controller层

/ssmbuild03/src/main/java/com/kuang/controller/BookController.java

    //查询书籍
    @RequestMapping("/queryBook")
    public String queryBook(String queryBookName,Model model) {
    	Books books = bookService.queryBookName(queryBookName);
    	//由于allbook展示页面需要list类型存入
    	//所以将获得books存入list中,然后跳转展示页面
    	List<Books> list = new ArrayList<Books>();
    	list.add(books);
    	//如果查询为空,就到显示页面
    	if (books==null) {
			list=bookService.queryAllBook();
			model.addAttribute("error","未查到");
		}
    	model.addAttribute("list", list);
    	
        return "allbook";
    }
  1. 将查询结果传到新的展示页面"allbook",并呈现
  2. 但由于展示页面使用的List集合,所以需要将传入的值传到到List集合中
  3. 同时判断如果查询值为空,就呈现全部书籍展示页面
  4. 同时发出 “未查到” 提示

前端

allbook.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>书籍展示</title>

<%-- BootStrap 美化界面 --%>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>
<%-- container一种格式边框 --%>
<div class="container">
	<%-- 清除浮动 --%>
	<div class="row clearfix">
		<%-- 分割,将屏幕横向分成12份,md屏幕大小,12占满全部12份 --%>
		<div class="col-md-12 column">
			<%-- 头部 --%>
			<div class="page-header">
				<%-- small标签 --%>
				<h1>
					<small>书籍列表 ———— 显示所有书籍</small>
				</h1>
			</div>
		</div>
	</div>
	
	<div class="row clearfix">
	<%-- 利用class="col-md-4 column",将内容分为三块。
		class="btn btn-primary" 模型
		style="float:right" 最右边
		 
	 --%>
		<div class="col-md-4 column">
			<%-- toAddBook --%>
			<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
			<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/allBook">显示全部书籍</a>
		</div>
		<div class="col-md-4 column"></div>
		<div class="col-md-4 column">
				
				<%-- 查询数据,需要使用form表单,a标签不能使用查询,form-inline变成一排的内联表单 --%>
			<form class="form-inline" action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float:right">
				<span style="color:red;">${error}</span>
				<input type="text" name="queryBookName" class="form-control" placeholder="请输入书籍名称">
				<input type="submit" value="查询" class="btn btn-primary">
			</form>
		</div>
	</div>
	
	<div class="row clearfix">
		<div class="col-md-12 column">
			<table class="table table-hover table-striped">
				<thead>
					<tr>
						<th>书籍编号</th>
						<th>书籍名称</th>
						<th>书籍数量</th>
						<th>书籍详情</th>
						<th>操作</th>
					</tr>
				</thead>
				<%-- 书籍从数据库中查询出来,从这个list中遍历出来:forEach(注意抬头引用) --%>
				<tbody>
				<%-- 获取数据 --%>
					<c:forEach var="book" items="${list}">
						<tr>
							<td>${book.bookID}</td>
							<td>${book.bookName}</td>
							<td>${book.bookCounts}</td>
							<td>${book.detail}</td>
							<td>
								<%-- 发送修改消息,并且发现修改对象的id,让修改的时候可以看到对象值 --%>
								<a href="${pageContext.request.contextPath}/book/toUpdate?id=${book.bookID}">修改</a>
								&nbsp; | &nbsp;
								<a href="${pageContext.request.contextPath}/book/deleteBook/${book.bookID}">删除</a>
								
							</td>
						</tr>
					</c:forEach>
				</tbody>
			</table>
		
		</div>
	</div>

</div>
</body>
</html>
  1. 首先使用from标签增加了查询功能
  2. 使用form-inline将表单变成一排的内联表单,同时${error} “未查到” 提示
  3. 添加一个查询完显示全部书籍的按键

Bootstrap可视化布局https://www.bootcss.com/p/layoutit/帮助前端设计,可以直接获得代码

Ajax

一、简介

  • AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

  • AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

  • Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。

  • 在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。

  • Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

  • 就和国内百度的搜索框一样!

在这里插入图片描述

  • 传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。

  • 使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。

  • 使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。

二、伪造Ajax

我们可以使用前端的一个标签来伪造一个ajax的样子。iframe标签

  1. 先设计一个计划弹窗的网页,不需要输入地址,只需要一个尺寸
  2. 设计一个用户输入网址,然后点击按钮事件
  3. 将输入的网址呈现到弹窗的网页上
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>iframe测试体验页面无刷新</title>
	
	<!-- 所有的值变量,提前获取 -->
<script>
	function go(){
		var url = document.getElementById("url").value;
		document.getElementById("iframe1").src=url;
	}
</script>
</head>
<body>

<div>
	<p>请输入地址:</p>
	<p>
		<input type="text" id="url" >
		<input type="button" value="提交" onclick="go()">
	</p>

</div>


<div>
	<iframe id="iframe1" style="width:100%;height:500px"></iframe>
</div>

</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>kuangshen</title>
</head>
<body>
 
<script type="text/javascript">
    window.onload = function(){
        var myDate = new Date();
        document.getElementById('currentTime').innerText = myDate.getTime();
    };
 
    function LoadPage(){
        var targetUrl =  document.getElementById('url').value;
        console.log(targetUrl);
        document.getElementById("iframePosition").src = targetUrl;
    }
 
</script>
 
<div>
    <p>请输入要加载的地址:<span id="currentTime"></span></p>
    <p>
        <input id="url" type="text" value="https://www.baidu.com/"/>
        <input type="button" value="提交" onclick="LoadPage()">
    </p>
</div>
 
<div>
    <h3>加载页面位置:</h3>
    <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
</div>
 
</body>
</html>

利用AJAX可以做:

  • 注册时,输入用户名自动检测用户是否已经存在。
  • 登陆时,提示用户名密码错误
  • 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。
  • …等等

三、jQuery.ajax

纯JS原生实现Ajax我们不去讲解这里,直接使用jquery提供的,方便学习和使用,避免重复造轮子,有兴趣的同学可以去了解下JS原生XMLHttpRequest !

Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。

jQuery 提供多个与 AJAX 有关的方法。

通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。

jQuery 不是生产者,而是大自然搬运工。

jQuery 是一个库;js 的大量函数(方法)

jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用!

jQuery.ajax(...)
       部分参数:
              url:请求地址
             type:请求方式,GET、POST(1.9.0之后用method)
          headers:请求头
             data:要发送的数据
      contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
            async:是否异步
          timeout:设置请求超时时间(毫秒)
       beforeSend:发送请求前执行的函数(全局)
         complete:完成之后执行的回调函数(全局)
          success:成功之后执行的回调函数(全局)
            error:失败之后执行的回调函数(全局)
          accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
         dataType:将服务器端返回的数据转换成指定类型
            "xml": 将服务器端返回的内容转换成xml格式
           "text": 将服务器端返回的内容转换成普通文本格式
           "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
         "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
           "json": 将服务器端返回的内容转换成相应的JavaScript对象
          "jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

/springmvc-06/src/main/resources/applicationContext.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:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           https://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 -->
	<context:component-scan
		base-package="com.kuang.controller" />
		
	<!-- 静态资源过滤js使用 -->
    <mvc:default-servlet-handler />

	<mvc:annotation-driven/>
	<!-- 视图解析器 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		id="internalResourceViewResolver">
		<!-- 前缀 -->
		<property name="prefix" value="/WEB-INF/jsp/" />
		<!-- 后缀 -->
		<property name="suffix" value=".jsp" />
	</bean>

</beans>

/springmvc-06/src/main/java/com/kuang/controller/AjaxController.java

package com.kuang.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AjaxController {
	@RequestMapping("/t1")
	public String test() {
		return "hello";
	}
	//测试环境是否成功
	
	@RequestMapping("/a1")
	public void a1(String name,HttpServletResponse response) throws IOException {
		System.out.println("a1:param->"+name);
		if ("kuangshen".equals(name)) {
			response.getWriter().print("true");
		}else {
			response.getWriter().print("false");
		}
	}
	
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
	function a(){
		<%-- 
		url:获取请求地址a1
		data:传递数据,$("#username").val()获取到输入值,存入a1.name
		success:回调函数function(data);error:function()失败
		alert:是否异步
		 --%>
		$.post({
			url:"${pageContext.request.contextPath}/a1",

			data:{"name":$("#username").val()},
			success:function(data){
				alert(data);
			}
		})
	}
	
</script>

</head>
<body>

<%-- 失去焦点的时候,发起一个请求到后台,onblur失去焦点事件 --%>
用户名:<input type="text" id="username" οnblur="a()">

</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" 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">

    <!--DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!-->  
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!--encodingFilter-->
    <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>/*</url-pattern>
    </filter-mapping>

</web-app>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.kuang</groupId>
	<artifactId>springmvc-06</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<dependencies>
		<!--Junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<!--数据库驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.47</version>
		</dependency>
		<!-- 数据库连接池 -->
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.2</version>
		</dependency>

		<!--Servlet - JSP -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!--Mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.2</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>2.0.2</version>
		</dependency>

		<!--Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.1.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.1.9.RELEASE</version>
		</dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.4</version>
    </dependency>

	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.3.1</version>
			</plugin>
		</plugins>

		<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.properties</include>
					<include>**/*.xml</include>
				</includes>
				<filtering>false</filtering>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*.properties</include>
					<include>**/*.xml</include>
				</includes>
				<filtering>false</filtering>
			</resource>
		</resources>
	</build>


</project>

测试结果

在这里插入图片描述

程序运行步骤

在这里插入图片描述

前段知识最少得要求:HTML + css:略懂 + js (超级熟练)

js:

  • 函数:闭包()()
  • Dom
    • id , name , tag
    • create , remove
  • Bom
    • window
    • document

ES6:import require

状态status

success:function(data,status){
				console.log("data="+data);
				console.log("status="+status);	//200成功,300重定向或者转发,400客户端错误,500服务器端错误
			}error(){

}

在这里插入图片描述

四、Ajax异步加载数据

创建实体类

/springmvc-06/src/main/java/com/kuang/pojo/User.java

package com.kuang.pojo;

public class User {
	private String name;
	private int age;
	private String sex;
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	public User(String name, int age, String sex) {
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
}

添加数据

/springmvc-06/src/main/java/com/kuang/controller/AjaxController.java

package com.kuang.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.kuang.pojo.User;

@RestController
//RestController不会返回到视图解析器去
public class AjaxController {
	@RequestMapping("/t1")
	public String test() {
		return "hello";
	}
	//测试环境是否成功
	
	@RequestMapping("/a1")
	public void a1(String name,HttpServletResponse response) throws IOException {
		System.out.println("a1:param->"+name);
		if ("kuangshen".equals(name)) {
			response.getWriter().print("true");
		}else {
			response.getWriter().print("false");
		}
	}
	//将对象返回到前段
	@RequestMapping("/a2")
	public List<User> a2(){
		List<User> userList = new ArrayList<User>();
		//添加数据
			userList.add(new User("狂神说java", 1, "男"));
			userList.add(new User("狂神说前端", 2, "女"));
			userList.add(new User("狂神说运维", 3, "男"));
		return userList;
	}
	
}

  • RestController不会返回到视图解析器去
  • 利用list将对象返回到前段
  • 对于前端,后端就是增删改查

创建Ajax异步加载器

test2.jsp

  1. 画页面<table>,展示<tr>,数据<tbody>(但是数据在后台,所以需要利用ajax请求获取数据)
  2. 加载jquery,利用id选择器<script>去获取,click点击事件
  3. 直接将请求简写到post中,获取返回值data,这里我们已经可以正常获取资源。
  4. 将返回的数据输入到异步块上。增加节点,拼接前端
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
	<title>Insert title here</title>
	<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
    <script>
        $(function(){
           $("#btn").click(function(){
            /*
            	$.post(url,param(可以省略),success)
            */
            $.post("${pageContext.request.contextPath}/a2",function(data) {
                //console.log(data);
                var html="";  
                   
                //JavaScript6新特性,var外面也可以调用,let只能在for用使用
                
                for(var i = 0; i < data.length;i++){
                	html += "<tr>" +
                        "<td>" + data[i].name + "</td>"+
                        "<td>" + data[i].age + "</td>"+
                        "<td>" + data[i].sex + "</td>"+
                        "</tr>"
            	}
               $("#content").html(html);
            });
       	  })
        });	
    </script>
<body>
    
    <input type="button" value="加载数据" id="btn">
    <table>
        <tr>
            <td>姓名</td>
        	<td>年龄</td>
        	<td>性别</td>
        </tr>
        <tbody id="content">
        	<%-- 数据:后台 --%>
        </tbody>
    </table>
</body>   
</head>

在这里插入图片描述

五、Ajax验证用户名体验

在这里插入图片描述

动态请求响应,局部刷新

请求页面

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script
	src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
	function a1(){
		$.post({
			url:"${pageContext.request.contextPath}/a3",
			data:{"name":$("#name").val()},
			<%-- success回调函数 --%>
			success:function(data){
				if(data.toString()==='ok'){
					$("#userInfo").css("color","green");
				}else{
					$("#userInfo").css("color","red");
				}
				$("#userInfo").html(data);
			}
		})
	}
	function a2(){
		$.post({
			url:"${pageContext.request.contextPath}/a3",
			data:{"pwd":$("#pwd").val()},
			<%-- success回调函数 --%>
			success:function(data){
				if(data.toString()==='ok'){
					$("#pwdInfo").css("color","green");
				}else{
					$("#pwdInfo").css("color","red");
				}
				$("#pwdInfo").html(data);
			}
		})
	}

</script>
</head>
<body>

<p>
    用户名:<input type="text" id="name" οnblur="a1()"/>
    <span id="userInfo"></span>
</p>
<p>
    密码:<input type="text" id="pwd" οnblur="a2()"/>
    <span id="pwdInfo"></span>
</p>

</body>
</html>

Controller.java

	@RequestMapping("/a3")
	public String a3(String name,String pwd){
		String msg ="";
		if(name!=null) {
			//admin应该为数据库信息
			if ("admin".equals(name)) {
				msg="ok";
			}else {
				msg="false";
			}
		}
		if(pwd!=null) {
			
			if ("123456".equals(pwd)) {
				msg="ok";
			}else {
				msg="false";
			}
		}	
		return msg;
	}

json乱码问题

	<mvc:annotation-driven>
   <mvc:message-converters register-defaults="true">
       <bean class="org.springframework.http.converter.StringHttpMessageConverter">
           <constructor-arg value="UTF-8"/>
       </bean>
       <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
           <property name="objectMapper">
               <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                   <property name="failOnEmptyBeans" value="false"/>
               </bean>
           </property>
       </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

问题解决

1、List 返回报错

报错No converter found for return value of type: class java.util.ArrayList]

解决办法,pom增加jackson依赖

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.4</version>
    </dependency>

https://www.cnblogs.com/zhoujian43/p/6640804.html

和Context.xml

<mvc:annotation-driven/>

想他们依赖多个jackson,可能会报下面的错误

  <properties>
    <jackson.version>2.5.4</jackson.version>
  </properties> 

  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>

Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter': Instantiation of bean failed; nested exception is

网站

拦截器

一、概述

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

过滤器与拦截器的区别:拦截器是AOP思想的具体应用。

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

二、自定义拦截器

那如何实现拦截器呢?

想要自定义拦截器,必须实现 HandlerInterceptor 接口

1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持

2、配置web.xml 和 springmvc-servlet.xml 文件

/springmvc-07/src/main/java/com/kuang/controller/Textcontroller.java

package com.kuang.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Textcontroller {
	@GetMapping("/t1")
	public String test() {
		System.out.println("Textcontroller---test");
		return "ok";
		
	}
}

applicationContext.xml

	<!-- 拦截器配置 -->
	<mvc:interceptors>
		<mvc:interceptor>
		<!-- 包括这个请求下面的所有的请求 -->
			<mvc:mapping path="/**"/>
			<!-- 谁去拦截 -->
			<bean class="com.kuang.config.MyInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>

3、编写一个拦截器

/springmvc-07/src/main/java/com/kuang/config/MyInterceptor.java

package com.kuang.config;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor implements HandlerInterceptor{
	
	//return ture ;执行下一个拦截器,方向
	//return false;不执行下一个拦截器
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("--------------处理前-----------");
		return true;
	}
	//主要用上面的,下面主要功能是拦截日志
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("--------------处理后-----------");
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("--------------清理中-----------");
	}
	
}

三、登录判断验证

创建一个主页

有登录页面(按钮)和首页(按钮)

/springmvc-07/src/main/webapp/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1><a href="${pageContext.request.contextPath}/goLogin">登录页面</a></h1>
<h1><a href="${pageContext.request.contextPath}/main">首页</a></h1>


</body>
</html>

创建一个前端控制层

  • 登录页面(按钮)—转—登录页面.jsp
  • 首页(按钮)—转—首页.jsp
  • 将登录页面.jsp内用户名信息存入session中

/springmvc-07/src/main/java/com/kuang/controller/LoginController.java

package com.kuang.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class LoginController {
	@RequestMapping("/main")
	public String main() {
		
		return "main";
	}
	@RequestMapping("/goLogin")
	public String login() {
		
		return "login";
	}
	
	@RequestMapping("/login")
	public String login(HttpSession session,String username,String password,Model model) {
		//把用户的信息存在session中,方便向下传递;
        //model 返回用户信息
		session.setAttribute("userLoginInfo", username);
		model.addAttribute("username", username);
        
		return "main";
	}
}

创建一个登录页面

/springmvc-07/src/main/webapp/jsp/login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- 在web-inf下的所有页面或者资源,只能通过controller,或者sevlet进行访问 -->
<h1>登录页面</h1>

<form action="${pageContext.request.contextPath}/user/login" method="post">
	用户名:<input type="text" name="username"/>
	密码:<input type="text" name="password"/>
	<input type="submit" value="提交"/>	
</form>
	
</body>
</html>

首页

/springmvc-07/src/main/webapp/jsp/main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>首页</h1>
    
<!-- 首页显示用户信息 -->
<span>${username}</span>

</body>
</html>

编写一个新拦截器

拦截未登录的用户,不能查看首页

/springmvc-07/src/main/java/com/kuang/config/LoginInterceptor.java

public class LoginInterceptor implements HandlerInterceptor{
	

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
        //放行:判断什么情况下需要登录
        
        HttpSession session = request.getSession();
       //登录页面直接放行
        if(request.getRequestURI().contains("goLogin")){
            return true;
        }
        //说明我在提交登录
        if(request.getRequestURI().contains("login")){
            return true;
        }
        
        //用户session有值的时候
        if(session.getAttribute("userLoginInfo")!=null){
            return true;
        }
        
        //判断什么情况下没有登录
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
		return false;
	}
}

?疑问:Login放行?那即使账号不正确或者不输入会不会也能登陆?

applicationContext.xml配置拦截器

添加LoginInterceptor父类user, 只拦截父类user目录下的所有请求

	<!-- 拦截器配置 -->
	<mvc:interceptors>
		<mvc:interceptor>
		<!-- 包括这个请求下面的所有的请求 -->
			<mvc:mapping path="/user/**"/>
			<!-- 谁去拦截 -->
			<bean class="com.kuang.config.LoginInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>

增加注销功能

注销动作,同时在login中添加Model获取用户信息

/springmvc-07/src/main/java/com/kuang/controller/LoginController.java

	@RequestMapping("/login")
	public String login(HttpSession session,String username,String password,Model model) {
		//把用户的信息存在session中,方便向下传递;
		session.setAttribute("userLoginInfo", username);
		model.addAttribute("username",username);
		return "main";
	}	

	@RequestMapping("/goOut")
	public String goOut(HttpSession session) {
		//删除指定attr对象
		session.removeAttribute("userLoginInfo");
		
		return "main";
	}

首页

/springmvc-07/src/main/webapp/jsp/main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>首页</h1>

<!-- 首页显示用户信息 -->
用户信息:<span>${username}</span>
    
<p>
	<a href="${pageContext.request.contextPath}/user/goOut">注销</a>    
</p>

</body>
</html>

?疑问:首页显示用户信息后,再次刷新网页用户信息就为空了

文件上传和下载

文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。

前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;

对表单中的 enctype 属性做个详细的说明:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
<form action="" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit">
</form>

一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
  • 而Spring MVC则提供了更简单的封装。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
  • CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

一、文件上传

1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;

<!--文件上传-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>

2、配置bean:multipartResolver

注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
    <property name="defaultEncoding" value="utf-8"/>
    <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="40960"/>
</bean>

CommonsMultipartFile 的 常用方法:

String getOriginalFilename():获取上传文件的原名

InputStream getInputStream():获取文件流

void transferTo(File dest):将上传文件保存到一个目录文件中

我们去实际测试一下

3、编写前端页面

<form action="/upload" enctype="multipart/form-data" method="post">
  <input type="file" name="file"/>
  <input type="submit" value="upload">
</form>

4、Controller

package com.kuang.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
 
import javax.servlet.http.HttpServletRequest;
import java.io.*;
 
@Controller
public class FileController {
    //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
    //批量上传CommonsMultipartFile则为数组即可
    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
 
        //获取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();
 
        //如果文件名为空,直接回到首页!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        System.out.println("上传文件名 : "+uploadFileName);
 
        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        //如果路径不存在,创建一个
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        System.out.println("上传文件保存地址:"+realPath);
 
        InputStream is = file.getInputStream(); //文件输入流
        OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
 
        //读取写出
        int len=0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();
        return "redirect:/index.jsp";
    }
}

5、测试上传文件,OK!

采用file.Transto 来保存上传的文件

1、编写Controller

/*
 * 采用file.Transto 来保存上传的文件
 */
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
 
    //上传路径保存设置
    String path = request.getServletContext().getRealPath("/upload");
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
    }
    //上传文件地址
    System.out.println("上传文件保存地址:"+realPath);
 
    //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
 
    return "redirect:/index.jsp";
}

2、前端表单提交地址修改

3、访问提交测试,OK!

二、文件下载

1、设置 response 响应头

2、读取文件 – InputStream

3、写出文件 – OutputStream

4、执行操作

5、关闭流 (先开后关)

代码实现:

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
    
    //修改只需要改这个位置
    //要下载的图片地址
    String  path = request.getServletContext().getRealPath("/upload");
    String  fileName = "基础语法.jpg";
 
    //1、设置response 响应头
    response.reset(); //设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8"); //字符编码
    response.setContentType("multipart/form-data"); //二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition",
            "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
 
    File file = new File(path,fileName);
    //2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、 写出文件--输出流
    OutputStream out = response.getOutputStream();
 
    byte[] buff =new byte[1024];
    int index=0;
    //4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
    }
    out.close();
    input.close();
    return null;
}

前端

<a href="/download">点击下载</a>

测试,文件下载OK,大家可以和我们之前学习的JavaWeb原生的方式对比一下,就可以知道这个便捷多了!

拦截器及文件操作在我们开发中十分重要,一定要学会使用!

更简单的方法

如果创建一个statics文件夹,存放1.png

<a href="${pageContext.request.contextPath}/statics/1.png">下载图片</a>

直接使用a标签获取这个文件,获取这个文件就会下载

SSM整合回顾

在这里插入图片描述

这篇关于SSM整合---狂神说Java学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!