Spring MVC实现RESTful风格

一、什么是Restful风格?

Restful风格指的是网络应用中就是资源定位和资源操作的风格。不是标准也不是协议。
Rest即Representational State Transfer的缩写,可译为"表现层状态转化”。Restful风格最大的特点为:资源、统一接口、URI和无状态。
这种风格设计的软件,可以更简洁,更有层次,更易于实现缓存等机制。

二、RESTful风格示例

以用户(User)的增删改查为例,我们可以设计出一下接口形式:每列分别对应,(请求类型:请求地址:功能描述)

  • get : /user/list :获取所有用户信息
  • post:/user:创建用户信息
  • put:/user:更新用户信息
  • get:/user/1:获取资源标识(id)为1的用户信息
  • delete:/user/1:删除资源标识(id)为1的用户信息

三、Spring MVC实现RESTful步骤

1. 通过@RequestMapping 注解的路径设置

当请求中携带的参数是通过请求路径传递到服务器中时,可以在 @RequestMapping 注解的 value 属性中通过占位符 {xxx} 来表示传递的参数,示例代码如下。

@RequestMapping("/product/{action}/{productId}")

注意:value 属性中占位符的位置应当与请求 URL 中参数的位置保持一致,否则会出现传错参数的情况。

2. 通过 @PathVariable 注解绑定参数

可以在控制器方法的形参位置通过 @PathVariable 注解,将占位符 {xxx} 所表示的参数赋值给指定的形参。

@RequestMapping("/product/{action}/{productId}")
    public String testFindProductById(@PathVariable("action") String action,@PathVariable("productId")Integer productId, Model model){
        //根据商品id查询出来商品信息对象
        Product product = productService.findProductById(productId);

        //往前台传数据,可以传对象,可以传List,前台通过表达式 ${}可以获取到
        model.addAttribute("product", product);
        //根据参数 action 判断跳转到商品详细信息页面还是商品修改页面
        if(action.equals("get")){
            return "product";
        }else{
            return "product_update";
        }
    }

3. 通过 HiddenHttpMethodFilter 对请求进行过滤

浏览器默认只支持发送 GET 和 POST 方法的请求,因此需要在 web.xml (要放在编码过滤器之下,不然会出现中文编码错误)中使用 Spring MVC 提供的 HiddenHttpMethodFilter 对请求进行过滤。这个过滤器可以帮助我们将 POST 请求转换为 PUT 或 DELETE 请求,其具体配置内容如下。

<!--来处理 PUT 和 DELETE 请求的过滤器-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

HiddenHttpMethodFilter 处理 PUT 和 DELETE 请求时,必须满足以下 2 个条件:

  • 当前请求的请求方式必须为 POST;
  • 当前请求必须传输请求参数 _method。

在满足了以上条件后,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数 _method 的值,即请求参数 _method 的值才是最终的请求方式,因此我们需要在 POST 请求中携带一个名为 _method 的参数,参数值为 DELETE 或 PUT。

注意:若 web.xml 中同时存在 CharacterEncodingFilter 和 HiddenHttpMethodFilter 两个过滤器,必须先注册 CharacterEncodingFilter,再注册 HiddenHttpMethodFilter。

四、案例实现

实现用户登录后,展示商品信息,同时在页面中可以实现对于产品信息的增、删、改、查

4.1创建项目

 

4.2.项目初始化\在pom.xml.添加依赖

  <dependencies>
    <!-- spring核心容器包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.18</version>
    </dependency>

    <!-- spring切面  -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.18</version>
    </dependency>

    <!--aop联盟包-->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>

    <!-- 德鲁伊连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.8</version>
    </dependency>

    <!--MySQL驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.28</version>
    </dependency>

    <!-- spring jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.3.20</version>
    </dependency>

    <!-- MySQL事务包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.3.18</version>
    </dependency>

    <!-- spring-orm映射依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>5.3.18</version>
    </dependency>

    <!-- Apache Commons日志包 -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- log4j2 日志 -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <version>2.17.1</version>
      <scope>test</scope>
    </dependency>

    <!-- lombok包 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
      <scope>provided</scope>
    </dependency>

    <!-- spring test测试支持包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.3.18</version>
      <scope>test</scope>
    </dependency>

    <!-- junit5单元测试 -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.8.2</version>
      <scope>test</scope>
    </dependency>

    <!-- springMVC支持包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.20</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.20</version>
    </dependency>

    <!-- JSON支持 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.13.3</version>
    </dependency>

    <!-- mybatis核心 jar包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>

    <!-- mybatis-spring整合包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.6</version>
    </dependency>

    <!--jsp 和Servlet  可选-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring5</artifactId>
      <version>3.1.0.M2</version>
    </dependency>

  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
        </includes>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

4.3.补充项目结构,准备好MVC模式下的主要目录

注意:要通过 Mark Directory as 将补充的目录进行设置,选择的参数说明:

  • Sources Root:告诉idea这个文件夹及其子文件夹中包含源代码,是需要编译构建的一部分
  • Test Sources Root:测试源文件夹允许您将与测试相关的代码与生产代码分开。通常,源和测试源的编译结果被放置在不同的文件夹中。
  • Resources Root:用于应用程序中的资源文件(图像、各种配置XML和属性文件等)。
  • 在构建过程中,资源文件夹的所有内容都复制到输出文件夹中,如下所示。
  • 类似于源,您可以指定生成资源。您还可以指定输出文件夹中的文件夹,您的资源应该复制到
  • Test Resources Root:测试的资源文件
  • Exclued:不包括、排除

4.4.更新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">
  <!--spring核心配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!--
   ContextLoaderListener监听器
   (1)ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
   (2)在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
   -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--请求和响应的字符串过滤器-->
  <filter>
    <filter-name>CharacterEncodingFilter</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>
    <!--设置响应的编码,这里我们可以省略-->
    <init-param>
      <param-name>forceResponseEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


  <!--来处理 PUT 和 DELETE 请求的过滤器-->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!--配置springMvc前端控制器,对浏览器发送的请求统一处理-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置DispatcherServlet的一个初始化参数:spring mvc配置文件的位置和名称-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <!--设置springmvc的核心控制器所能处理的请求路径 /所匹配的请求可以是 /login 或者 .html 或者.js或者css请求路径
    但是/不能匹配.jsp请求的路径的请求
    -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>


</web-app>

4.5.在resource目录下准备配置文件

4.5.1.创建 log4j2.xml 内容如下

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <Console name="Console" target="SYSTEM_ERR">
            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %Augus%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

4.5.2.创建 jdbc.properties内容如下

jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc_username=root
jdbc_password=123456

4.5.3.创建 springmvc.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">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.augus.controller"></context:component-scan>

    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 配置 Thymeleaf 视图解析器 -->
    <bean id="viewResolver"
          class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <!--配置静态资源放行-->
    <mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
    <mvc:resources mapping="/upload/**" location="/upload/"></mvc:resources>

</beans>

4.5.4.创建 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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/util
       http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
    <!--加载外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!--扫描service层-->
    <context:component-scan base-package="com.augus.service"></context:component-scan>

    <!--配置德鲁伊连接池-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc_username}"></property>
        <property name="password" value="${jdbc_password}"></property>
        <property name="url" value="${jdbc_url}"></property>
        <property name="driverClassName" value="${jdbc_driver}"></property>
    </bean>

    <!--
    SqlSessionFactoryBean能在Spring IoC容器中以SqlSessionFactory的类型保存并被获取。就是继承了FactoryBean这个接口了,这是个支持泛型的接口:
    当实现了这个接口的Bean在配置为被Spring接管时,存入IoC容器中的实例类型将会是实例化泛型的那个类型,从IoC容器中获取时也是实例化泛型的那个类型,
    这种情况下,Spring 将会在应用启动时为你创建SqlSessionFactory对象,然后将它以 SqlSessionFactory为名来存储。当把这个bean注入到Spring中去了以后,IoC容器中的其他类型就可以拿到SqlSession实例了,就可以进行相关的SQL执行任务了。
    -->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--获取上面的数据源-->
        <property name="dataSource" ref="druidDataSource"></property>
        <property name="typeAliasesPackage" value="com.augus.pojo"></property>
    </bean>

    <!--
    配置MapperScanner 扫描mapper.xml接口
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--配置SQLSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"></property>
        <!--配置mapper扫描-->
        <property name="basePackage" value="com.augus.mapper"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
</beans>

4.6.在数据库中创建表

  • user表
CREATE TABLE `user` (
  `uid` int(255) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`uid`)
)
  • product表
CREATE TABLE `product` (
  `productid` int(11) NOT NULL AUTO_INCREMENT,
  `productname` varchar(255) DEFAULT NULL,
  `price` double DEFAULT NULL,
  `storage` int(255) DEFAULT NULL,
  PRIMARY KEY (`productid`)
)

4.7.在WEB-INF/templates下前端页面

  • user.html:登录页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>欢迎来到ssm登录页面</title>
</head>
<body>
<form action="login" method="post">
    <table style="margin: auto;">
        <tr>
            <td colspan="2" align="center">
                <!--
                th:if="${not #strings.isEmpty(msg)}" 判断优先级高,先判断后生成(判断msg中是否为空)
                不为空,通过th:text="${msg}"取值显示
                -->
                <p style="color: red;margin: auto" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
            </td>
        </tr>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" required><br></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="text" name="password" required><br></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="提交" style="margin: auto;">
                <input type="reset" value="重置">
            </td>
        </tr>
    </table>
</form>
</body>
</html>
  • productList.html:登录后页面展示商品信息
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列出所有的商品</title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>
    <script type="text/javaScript">
        function testJson1(productId) {
            var b = confirm("确认删除id 为" + productId + " 的商品?");
            if (b) {
                var delete_form = $("#delete_form");
                //给id为#form-id的元素设置一个value属性值为productId
                $("#form-id").val(productId);
                delete_form.submit();
            }
        }
    </script>
</head>
<body>
<!--
session.loginUser.getUsername() 获取在登录验证通过后,通过session域传递过来的user2对象,并且获取用户名
-->
<h1 th:text="'欢迎您:'+${session.loginUser.getUsername()}" style="text-align:center;"></h1>
<table th:border="1" th:cellspacing="0" th:cellpadding="10" style="margin: auto;">
    <thead>
    <th>商品id</th>
    <th>商品名称</th>
    <th>商品价格</th>
    <th>商品库存</th>
    <th>操作</th>
    </thead>
    <tbody>
    <!--
    Thymleaf使用th:each遍历表格
    -->
    <tr th:each="product:${productList}">
        <!--
        如果是需要从model中取值的话 写法为th:text="${model的name}"
        -->
        <td th:text="${product.getProductId()}"></td>
        <td th:text="${product.getProductName()}"></td>
        <td th:text="${product.getPrice()}"></td>
        <td th:text="${product.getStorage()}"></td>
        <td>
            <a th:href="@{|/product/get/${product.getProductId()}|}">查看商品</a>
            <a th:href="@{|/product/update/${product.getProductId()}|}">修改商品</a>
            <a href="#" th:onclick="testJson1([[${product.getProductId()}]]);">删除商品</a>
        </td>
    </tr>

    </tbody>

    <br>
    <a th:href="@{/addPage}">新增商品</a>

<!--    &lt;!&ndash; 作用:通过超链接控制表单的提交,将post请求转换为delete请求 &ndash;&gt;-->
    <form id="delete_form" method="post" th:action="@{/product}">
        <!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 -->
        <input type="hidden" name="_method" value="delete"/>
        <input type="hidden" name="productId" id="form-id"/>
    </form>

</table>
</body>
</html>
  • product.html:展示商品详情页
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>商品信息展示</title>
</head>
<body>
<table style="margin: auto;">
    <tr>
        <td> 商品ID:</td>
        <td th:text="${product.getProductId()}"></td>
    </tr>
    <tr>
        <td>商品名称:</td>
        <td th:text="${product.getProductName()}"></td>
    </tr>
    <tr>
        <td>商品价格:</td>
        <td th:text="${product.getPrice()}"></td>
    </tr>
    <tr>
        <td>商品库存:</td>
        <td th:text="${product.getStorage()}"></td>
    </tr>
</table>
<p style="text-align: center"><a th:href="@{/findAllProduct}">返回商品列表</a></p>
</body>
</html>
</body>
</html>
  • product_add.html:新增商品页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>新增商品</title>
</head>
<body>
<form th:action="@{/product}" method="post">
    <table style="margin: auto">
        <tr>
            <td>商品 ID:</td>
            <td><input type="text" name="productId" required></td>
        </tr>
        <tr>
            <td>商品名称:</td>
            <td><input type="text" name="productName" required></td>
        </tr>
        <tr>
            <td>商品价格:</td>
            <td><input type="text" name="price" required></td>
        </tr>
        <tr>
            <td>商品库存:</td>
            <td><input type="text" name="storage" required></td>
        </tr>
        <tr>
            <td colspan="2" align="center"><input type="submit" value="新增商品"></td>
        </tr>
    </table>
</form>
</body>
</html>
  • product_update.html:修改商品信息
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改商品信息</title>
</head>
<body>
<form th:action="@{/product}" method="post">
    <input type="hidden" name="_method" value="put">
    <table style="margin: auto">
        <tr>
            <td>商品 ID:</td>
            <td><input type="text" name="productId" th:value="${product.getProductId()}" readonly></td>
        </tr>
        <tr>
            <td>商品名称:</td>
            <td><input type="text" name="productName" th:value="${product.getProductName()}" required></td>
        </tr>
        <tr>
            <td>商品价格:</td>
            <td><input type="text" name="price" th:value="${product.getPrice()}" required></td>
        </tr>
        <tr>
            <td>商品库存:</td>
            <td><input type="text" name="storage" th:value="${product.getStorage()}" required></td>
        </tr>
        <tr>
            <td colspan="2" align="center"><input type="submit" value="修改商品信息"></td>
        </tr>
    </table>
</form>
</body>
</html>

4.8.在java下创建包com.augusu,在分别创建四个包,如下

4.8.1.新建pojo包

在下面创建 User、Product实体类,代码如下

  • User
package com.augus.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {
    private Integer uid;
    private String username;
    private String password;
}
  • Product
package com.augus.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Product implements Serializable{
    private Integer productId;
    private String productName;
    private Double price;
    private Integer storage;
}

4.8.2.新建mapper包(作为持久层)

  • 在创建 UserMapper、UserMapper.xml
package com.augus.mapper;

import com.augus.pojo.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {
    User findByUserName(@Param("name") String username);
}
<?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.augus.mapper.UserMapper">
    <!--User findUser(String uname, String password);-->
    <select id="findByUserName" resultType="user">
        select * from user where username = #{name}
    </select>
</mapper>
  • 在创建ProductMapper、ProductMapper.xml
package com.augus.mapper;

import com.augus.pojo.Product;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface ProductMapper {
    List<Product> findAllProduct();

    Product findProductById(@Param("productId") Integer productId);

    int addProduct(Product product);

    int updateProduct(Product product);


    int deleteProduct(Integer productId);
}
<?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.augus.mapper.ProductMapper">

    <select id="findAllProduct" resultType="product">
        select * from product
    </select>

    <!--根据编号查询产品信息-->
    <select id="findProductById" resultType="product" parameterType="int">
        select * from product where productid = #{productId}
    </select>

    <!--新增产品信息-->
    <insert id="addProduct">
        insert into product values(DEFAULT , #{productName}, #{price}, #{storage})
    </insert>

    <!--修改产品信息-->
    <update id="updateProduct">
        update product set productname=#{productName},price=#{price},storage=#{storage} where productid=#{productId}
    </update>

    <!--根据编号删除商品信息-->
    <delete id="deleteProduct">
        delete from product where productid=#{productId}
    </delete>

</mapper>

4.8.3.新建service包

在下面创建 接口UserService、ProductService,同时在创建impl包里面创建 UserServiceImpl、ProductServiceImpl实现类

  • UserService
package com.augus.service;

import com.augus.pojo.User;

public interface UserService {
    User findByUserName(String uname);
}
  • UserServiceImpl
package com.augus.service.impl;

import com.augus.mapper.ProductMapper;
import com.augus.pojo.Product;
import com.augus.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;

    @Override
    public Product findProductById(Integer productId) {
        return productMapper.findProductById(productId);
    }

    @Override
    public List<Product> findAllProduct() {
        return productMapper.findAllProduct();
    }

    @Override
    public int addProduct(Product product) {
        return productMapper.addProduct(product);
    }

    @Override
    public int updateProduct(Product product) {
        return productMapper.updateProduct(product);
    }

    @Override
    public int deleteProduct(Integer productId) {
        return productMapper.deleteProduct(productId);
    }
}
  • ProductService
package com.augus.service;

import com.augus.pojo.Product;

import java.util.List;

public interface ProductService {
    Product findProductById(Integer productId);

    List<Product> findAllProduct();

    int addProduct(Product product);

    int updateProduct(Product product);

    int deleteProduct(Integer productId);
}
  • ProductServiceImpl
package com.augus.service.impl;

import com.augus.mapper.ProductMapper;
import com.augus.pojo.Product;
import com.augus.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;

    @Override
    public Product findProductById(Integer productId) {
        return productMapper.findProductById(productId);
    }

    @Override
    public List<Product> findAllProduct() {
        return productMapper.findAllProduct();
    }

    @Override
    public int addProduct(Product product) {
        return productMapper.addProduct(product);
    }

    @Override
    public int updateProduct(Product product) {
        return productMapper.updateProduct(product);
    }

    @Override
    public int deleteProduct(Integer productId) {
        return productMapper.deleteProduct(productId);
    }
}

4.8.4.新建controller包

  • 在下面创建 LoginController类,代码如下
package com.augus.controller;

import com.augus.pojo.User;
import com.augus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
    @Autowired
    private UserService userService;

    @RequestMapping("/user")
    public String testUser(){
        return "user";
    }

    @RequestMapping("/login")
    public String login(User user, HttpServletRequest request){
        //获取根据用户名 查询到的user对象
        User user2 = userService.findByUserName(user.getUsername());
        if(user2 != null && user2.getPassword().equals(user.getPassword())){
            //如果byUserName不为空,输入的密码和数据库中保存的密码保持一致,则表示登录成功,就写出产品信息
            HttpSession session = request.getSession();
            //将当前登录的user2对象放到session域中
            session.setAttribute("loginUser", user2);
            return "redirect:/findAllProduct";
        }
        request.setAttribute("msg","账户或者密码错误!!!");
        return "user";
    }
}
  • 在下面创建ProductController 类,代码如下
package com.augus.controller;

import com.augus.pojo.Product;
import com.augus.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;

@Controller
public class ProductController {

    @Autowired
    private ProductService productService;

    @RequestMapping("/findAllProduct")
    public ModelAndView testFindAllProduct(){

        ModelAndView modelAndView = new ModelAndView();
        //设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
        modelAndView.setViewName("productList");

        //获取所有的产品信息,存放到list集合中
        List<Product> productList = productService.findAllProduct();
        //添加模型数据 可以是任意的POJO对象也可以是任何java类型
        modelAndView.addObject(productList);

        return modelAndView;
    }

    /**
     * 查看或回显商品信息,get:查看商品信息  update:为修改页回显的商品信息
     * @param action
     * @param productId
     * @param model
     * @return
     */
    @RequestMapping("/product/{action}/{productId}")
    public String testFindProductById(@PathVariable("action") String action,@PathVariable("productId")Integer productId, Model model){
        //根据商品id查询出来商品信息对象
        Product product = productService.findProductById(productId);

        //往前台传数据,可以传对象,可以传List,前台通过表达式 ${}可以获取到
        model.addAttribute("product", product);
        //根据参数 action 判断跳转到商品详细信息页面还是商品修改页面
        if(action.equals("get")){
            return "product";
        }else{
            return "product_update";
        }
    }

    /**
     * 打开新增页面
     */
    @RequestMapping("/addPage")
    public String testAddPage(){
        return "product_add";
    }

    /**
     * 新增商品
     * @param product
     * @return
     */
    @RequestMapping(value = "/product", method = RequestMethod.POST)
    public String addProduct(Product product){
        productService.addProduct(product);
        //新增成功后,跳转到列出所有商品的页面
        return "redirect:/findAllProduct";
    }


    /**
     * 修改商品信息
     * @param product
     * @return
     */
    @RequestMapping(value = "/product", method = RequestMethod.PUT)
    public String updateProduct(Product product){
        productService.updateProduct(product);
        return "redirect:/findAllProduct";
    }

    /**
     * 删除商品
     * @param productId
     * @return
     */
    @RequestMapping(value = "product",method = RequestMethod.DELETE)
    public String deleteProduct(Integer productId){
        productService.deleteProduct(productId);
        return "redirect:/findAllProduct";
    }
}

4.9.重新部署项目

访问:http://localhost:8080/ssm01_war_exploded/user 如下:

 输入用户名和密码登录后,即可进入商品列表页面

点击新增商品即可进入到新增商品页面

点击 修改商品,即可进入商品信息修改页面,可对商品信息进行修改

点击 删除商品,即可对该商品进行删除

点击 查看商品,即可查看该商品的详细信息

posted @ 2022-10-03 18:04  酒剑仙*  阅读(274)  评论(2编辑  收藏  举报