SSM整合

SSM整合即Spring+SpringMVC+Mybatis,在了解SSM整合之前先回顾下MVC框架

MVC开发模式

现在的B/S系统大多都是遵从MVC的开发模式开发的。
M就是Model,模型层,负责数据的存储,就是代码中的类,最早的时候必须符合JavaBean的规范;
V就是View,视图层,负责信息的展示,就是用户看到的应用页面;
C就是Controller,控制器,这一层做的主要是逻辑层的操作,比如用户登录的后台代码,当然现在的逻辑层,在开发的过程中是由dao、service和controller共同组成的。


image.png

具体流程:
用户登录--->(Servlet(web层))接收用户的登录请求--->处理用户的请求( 获取用户登录的参数,username,password) ---->交给业务层(Service层)处理登录业务(判断用户名密码是否正确) --->Dao层查询用户名和密码是否正确-->数据库然后再一层层返回结果给用户。

SSM这三者的作用分别是什么呢?

<1> Spring

是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)
控制反转(IoC):是一种设计思想,DI(依赖注入)是一种实现IOC的方法
是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是Ioc容器,实现的方法是依赖注入。
依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源
注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配
而实际上是一个Bean(各种类都能称为Bean)的超级大工厂,只要是代码中哪里需要用到某个类,直接和Spring要就可以了。而以前我们只能用到哪个类就new一个,或者通过工厂模式。实际上这个大工厂被我们称作IOC(依赖注入),就是生成类的某种方式,这大大降低了代码的耦合性。
面向切面编程(Aop),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

<2>SpringMVC

SpringMVC,说SpringMVC是视图层的,这是肯定的。如果你用过Servlet+JSP的开发模式,你一定非常清楚,想要在一个JSP页面中绑定数据(数据显示在页面中),实际上是非常困难的,需要通过request的setAttribute方法,然后JSP页面上再来一个request.id之类的东西,总之非常不方便。还有就是Controller接收参数,如果要接收参数的话,Servlet的开发只能在get或者post方法中写参数的名字。如果参数非常多,可想而知,这得多么复杂。SpringMVC就非常简单了,如果我们想要接收很多参数的话,直接就能把这些参数封装在一个类中,把类放到参数的位置就好了,SpringMVC就会自动帮助我们完成参数接收的过程,非常方便。实际上,在这个过程中,依然有Spring框架中IOC模块的支持。

<3>Mybatis

是一款优秀的持久层框架,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 映射成数据库中的记录。mybatis只能算作是Controller层中的一部分,即dao。dao也叫做持久层,作用就是将数据持久化到数据库之类的东西里面,也就是ORM框架。Mybatis非常好用,以前我们做开发的时候,一般都是写JSBC,就算不直接用JDBC,还是会用DBUtils之类的数据库组件,但是这些组件并不灵活,稍微有些问题就无法读取或写入数据到数据库。Mybatis的出现大大解决了这个问题。

环境要求

IDEA

Tomcat7+

Mysql5.7..

Maven3.5+

项目的结构

image.png

在这个web项目中,大的目录分成了java、resources、webapp三部分。
java中有controller,这里面是存放控制器类的,这就类似于之前Servlet的作用。
dao,这是存放数据库映射文件的,功能和之前的JDBC相同。
pojo,这个目录是存放和数据库对应的基本类。
service,服务层,controller负责处理逻辑操作,service负责的是和dao层交互,实现具体的功能,比如插入一条数据,查询数据之类的。
resources,资源路径,多数的配置文件和Mybatis的映射文件都放在这里。
webapp,这里面的内容和之前的开发一样,只是多出来一个SpringMVC的配置文件。

我们将整体的结构分成了五个部分,分别是前端页面、Spring容器、数据库连接池、数据库、Maven依赖管理。

完成一个web请求的个过程大致如下:

前端页面发起一个http请求:localhost:8080/book
http请求被Tomcat服务器得到,接着到Servlet中寻找映射路径,当然有了SpringMVC就无需去执行复杂的配置了,我们可以像Servlet3.0那样使用注解开发,SpringMVC前端控制器的注解是@RequestMapping(”/book”),通过请求的url,寻找映射路径,找到对应Controller类的方法
在Controller中,注入了许多的Service,Controller可以直接调用这些service进行操作
controller调用Service后,Service就要执行对应的方法,在Service中同样注入了dao层的mapper,即可调用相应的mapper方法执行数据库操作
mybatis中,dao层分成两部分,分别是接口和mapper映射文件,调用mapper接口方法的时候,就会去找到对应方法的映射,这些映射就是执行数据库操作的语句,本质上还是sql语句。
完成controller操作以后,再通过SpringMVC前端控制器控制页面跳转或者重定向之类的操作,但是现在一般使用ajax技术,提高前端页面的性能。

1.数据库搭建

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,'从进门到进牢');

2.导入Maven

<dependencies>

<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.Mybatis层编写:

数据库配置文件 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=root

编写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>

<typeAliases>
    <package name="com.chen.pojo"/>
</typeAliases>
<mappers>
    <mapper resource="com/chen/dao/BookMapper.xml"/>
</mappers>

</configuration>

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

public class Books {
private int bookID;
private String bookName;
private int bookCounts;
private String detail;

别忘了设置对应的set get方法和有参无参方法

5.编写Dao层的 BookMapper接口

import java.util.List;

public interface BookMapper {
//增加一本书
int addBook(Books books);

//删除一本书
int deleteBookById(@Param("bookId") int id);

//修改一本书
int updateBook(Books books);

//查询一本书
Books queryBookById(@Param("bookId") int id);

//查询全部书
List<Books> queryAllBook();

//搜作书
Books queryBookByName(@Param("bookName") String bookName);
}

编写接口对应的 BookMapper.xml 文件。

<?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">
<!--=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.chen.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>

<select id="queryBookByName" resultType="Books">
    select * from ssmbuild.books where bookName = #{bookName}
</select>
</mapper>

6.编写Service层的接口和实现类

接口

import com.chen.pojo.Books;
import java.util.List;

public interface BookService {
//增加一本书
int addBook(Books books);

//删除一本书
int deleteBookById(int id);

//修改一本书
int updateBook(Books books);

//查询一本书
Books queryBookById(int id);

//查询全部书
List<Books> queryAllBook();

Books queryBookByName(String bookName);
}

实现类

package com.chen.service;

import com.chen.dao.BookMapper;
import com.chen.pojo.Books;
import org.springframework.stereotype.Service;

import java.util.List;

public class BookServiceImpl implements BookService {

private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
    this.bookMapper = bookMapper;
}

public int addBook(Books books) {
     return bookMapper.addBook(books);
}

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();
}

public Books queryBookByName(String bookName) {
    return bookMapper.queryBookByName(bookName);
}
}

到此,底层需求操作编写完毕!!

Spring层

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

我们去编写Spring整合Mybatis的相关的配置文件 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">

<!--    关联数据据库配置文件-->
    <context:property-placeholder     location="classpath:database.properties"/>

<!--    连接池-->
<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>

<!--    sqlSessionFactory-->
    <bean id="sqlSessionFactory"     class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
<!--        绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-    config.xml"/>
</bean>

<!--    配置扫描Dao接口包,动态的实现Dao接口可以注入到Spring容器中!-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--        注入sqlSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--        要扫描的dao包-->
        <property name="basePackage" value="com.chen.dao"/>
</bean>
</beans>

1.Spring整合service层

<?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.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

<!--    1.扫描service下的包-->
<context:component-scan base-package="com.chen.service"/>

<!--2.将我们的所有业务类,注入到Spring, 可以通过配置,或者注解实现-->
<bean id="BookServiceImpl" class="com.chen.service.BookServiceImpl">
    <property name="bookMapper" ref="bookMapper"/>
</bean>

<!--    3. 声明式事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <!--    注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>


  </beans>

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

SpringMVC层

1.web.xml

  <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
     version="4.0">
<!--    DispatchServlet-->
<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>
<!--     设置乱码过滤-->
<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>

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
    https://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/context
    https://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.chen.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>

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

@Controller
@RequestMapping("/book")
public class BookController {
    @Autowired
//    @Qualifier("BookServiceImpl")
private BookService bookService;

//查询所有的数据,返回到书籍展示页面
@RequestMapping("/allBook")
public String list(Model model){
    List<Books> books = bookService.queryAllBook();
    model.addAttribute("list",books);
    return "allBook";
}
//添加书籍页面
@RequestMapping("/toAddBook")
public String toAddPaper(){
    return "addBook";
}
@RequestMapping("/addBook")
public String addBook(Books books){
    bookService.addBook(books);
    return "redirect:/book/allBook";
}
//跳转到修改书籍页面
@RequestMapping("/toUpdateBook")
public String toUpdatePaper(int id,Model model){
    Books books = bookService.queryBookById(id);
    model.addAttribute("QBooks",books);
    return "updateBook";
}
//修改书籍
@RequestMapping("/updateBook")
public String updateBook(Books books){
    System.out.println("updateBook="+books);
    bookService.updateBook(books);
    return "redirect:/book/allBook";
}
//删除书籍
@RequestMapping("/deleteBook/{bookId}")
public String deleteBook(@PathVariable("bookId") int id){
    bookService.deleteBookById(id);
    return "redirect:/book/allBook";
}

//查询书籍
@RequestMapping("/queryBook")
public String queryBook(String queryBookName,Model model){
    Books books = bookService.queryBookByName(queryBookName);
    List<Books> list = new ArrayList<Books>();
    list.add(books);
    if(books==null){
        list = bookService.queryAllBook();
        model.addAttribute("error","查询的书籍不存在");
    }
    model.addAttribute("list",list);
    return "allBook";

}
}

剩余的jsp页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<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>

书籍列表页面 allbook.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书籍展示</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/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>

<div class="row">
    <div class="col-md-4 column">
        <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 class="col-md-4 column"></div>
<%--           查询书籍--%>
        <form class="form-inline" action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float: right">
            <input type="text"  name="queryBookName" 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>

            <tbody>
            <c:forEach var="book" items="${requestScope.get('list')}">
                <tr>
                    <td>${book.getBookID()}</td>
                    <td>${book.getBookName()}</td>
                    <td>${book.getBookCounts()}</td>
                    <td>${book.getDetail()}</td>
                    <td>
                        <a href="${pageContext.request.contextPath}/book/toUpdateBook?id=${book.getBookID()}">更改</a> |
                        <a href="${pageContext.request.contextPath}/book/deleteBook/${book.getBookID()}">删除</a>
                    </td>
                </tr>
            </c:forEach>
            </tbody>
        </table>
    </div>
</div>
</div>

</body>
</html>

添加书籍页面:addBook.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加书籍</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/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>

修改书籍页面 updateBook.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改书籍</title>
<html>
<head>
    <title>修改书籍</title>
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/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/updateBook" method="post">
    <input type="hidden" name="bookID" value="${QBooks.bookID}">
    书籍名称:<input type="text" name="bookName" value="${QBooks.bookName}" required><br><br><br>
    书籍数量:<input type="text" name="bookCounts" value="${QBooks.bookCounts}" required><br><br><br>
    书籍详情:<input type="text" name="detail" value="${QBooks.detail}" required><br><br><br>
    <input type="submit" value="修改">
</form>
</div>
</body>
</html>

这就是我的第一个SSM项目了。是在b站上看的,比较新的视频,19年10月份的,推荐大家去学学https://space.bilibili.com/95256449/channel/detail?cid=90797

image.png

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容