Spring+SpringJDBC+Servlet学习笔记,以超市订单管理系统为例

1.Spring总体技术体系

 

 框架 = jar包+配置文件

2.框架的优点

1.提高开发效率:框架提供了许多预先设计好了的组件和工具,能够帮助开发人员快速进行开发。相较于传统手写代码,在框架提供的规范化环境中,开发者可以更快地实现项目的各种要求。

2.降低开发成本:框架的提供标准化的编程语言、数据操作等代码片段,避免了重复开发的问题,降低了开发成本,提供深度优化的系统,降低了维护成本,增强了系统的可靠性。

3.提高应用程序的稳定性:框架通常经过了很长时间的开发和测试,其中的许多组件、代码片段和设计模式都得到了验证。重复利用这些组件有助于减少bug的出现,从而提高了应用程序的稳定性。

4.提供标准化的解决方案:框架通常是针对某个特定领域的,通过提供标准化的解决方案,可以为开发人员提供一种共同的语言和思想基础,有助于更好地沟通和协作。

3.框架的缺点 

1.学习成本高:框架通常具有特定的语言和编程范式。对于开发人员而言,需要花费时间学习其背后的架构、模式和逻辑,这对于新手而言可能会耗费较长时间。

2.可能存在局限性:虽然框架提高了开发效率并可以帮助开发人员解决常见问题,但是在某些情况下,特定的应用需求可能超出框架的范围,从而导致应用程序无法满足要求。开发人员可能需要更多的控制权和自由度,同时需要在框架和应用程序之间进行权衡取舍。

3.版本变更和兼容性问题:框架的版本发布和迭代通常会导致代码库的大规模变更,进而导致应用程序出现兼容性问题和漏洞。当框架变更时,需要考虑框架是否向下兼容,以及如何进行适当的测试、迁移和升级。

4.架构风险:框架涉及到很多抽象和概念,如果开发者没有足够的理解和掌握其架构,可能会导致系统出现设计和架构缺陷,从而影响系统的健康性和安全性。

4.组件

 常规的三层架构处理请求流程:

 整个项目就是由各种组件搭建而成的:

5.pom.xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.csi</groupId>
    <artifactId>sss</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-framework>5.3.37</spring-framework>
    </properties>

    <dependencies>
        <!--spring context依赖-->
        <!--当你引入SpringContext依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-framework}</version>
        </dependency>

        <!-- 数据库驱动和连接池-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.53</version>
        </dependency>


        <!-- spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-framework}</version>
        </dependency>

        <!--日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.8.0-beta4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.8.0-beta4</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>4.0.4</version>
            <scope>provided</scope>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring-framework}</version>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.11</version>
        </dependency>
    </dependencies>
</project>

6.web.xml配置

 在web.xml中,添加configLocation属性,能够找到Spring的核心配置文件

<?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">

    <!--获取核心配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!--配置Spring监听器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

7.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"
       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*:jdbc.properties" />

    <!-- 配置Druid数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="10"/>
        <property name="maxActive" value="20"/>
    </bean>

    <!-- 配置 JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 装配数据源 -->
        <constructor-arg name="dataSource" ref="dataSource"/>
    </bean>

<!--    配置dao与jabcTemplate对象的关系-->
  
    <bean id="userDao" class="com.csi.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <bean id="userService" class="com.csi.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
     </bean>
</beans>

 7.1Spring Ioc/DI实现步骤

7.1.1配置元数据

基于 XML 的配置元数据的基本结构: 

<bean id="..." [1] class="..." [2]>    
    <!-- collaborators and configuration for this bean go here -->
 </bean>

Spring IoC 容器管理一个或多个组件。这些 组件是使用你提供给容器的配置元数据(例如,以 XML <bean/> 定义的形式)创建的。

<bean /> 标签 == 组件信息声明

1.id 属性是标识单个 Bean 定义的字符串。

2.class 属性定义 Bean 的类型并使用完全限定的类名

7.12.实例化Ioc容器

 提供给 ApplicationContext 构造函数的位置路径是资源字符串地址,允许容器从各种外部资源(如本地文件系统、Java CLASSPATH 等)加载配置元数据。

//实例化ioc容器,读取外部配置文件,最终会在容器内进行ioc和di动作
ApplicationContext context = 
           new ClassPathXmlApplicationContext("applicationContext.xml");

7.1 3.获取Bean(组件) 

ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖项的注册表。通过使用方法 T getBean(String name, Class<T> requiredType) ,可以检索 bean 的实例。 允许读取 Bean 定义并访问它们 

//创建ioc容器对象,指定配置文件,ioc也开始实例组件对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取ioc容器的组件对象
UserDao userDao = (UserDao) context.getBean("userDao");
//使用组件对象        
User user = userDao.login("admin", "1");

 7.2基于XML配置方式组件管理

 7.2.1基于无参构造函数

当通过构造函数方法创建一个 bean(组件对象) 时,所有普通类都可以由 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 Bean 类信息就足够了。但是,默认情况下,我们需要一个默认(空)构造函数。

@Getter
@Setter
public class User {
    //默认包含无参数构造函数
    public void show() {
       System.out.println("我有默认无参构造函数");
    }
}

 创建携带spring约束的xml配置文件:resources/spring-bean-01.xml 

<bean id="userDao" class="com.csi.dao.impl.UserDaoImpl"/>
  • bean标签:通过配置bean标签告诉IoC容器需要创建对象的组件信息

  • id属性:bean的唯一标识,方便后期获取Bean!

  • class属性:组件类的全限定符!

  • 注意:要求当前组件类必须包含无参数构造函数!

7.2.2基于静态工厂方法实例化 

 除了使用构造函数实例化对象,还有一类是通过工厂模式实例化对象,以其他例子为例:

public class ClientService {
  private static ClientService clientService = new ClientService();
  private ClientService() {}
    public static ClientService createInstance() {
            return clientService;
    }
}
...
<bean id="clientService"
  class="examples.ClientService"
  factory-method="createInstance"/>
  • class属性:指定工厂类的全限定符!

  • factory-method: 指定静态工厂方法,注意,该方法必须是static方法。

7.2.3基于实例工厂方法实例化

 使用实例工厂方法创建Bean的配置

public class DefaultServiceLocator {
  private ClientServiceImpl clientService = new ClientServiceImpl();
    public ClientService createClientServiceInstance() {
    return clientService;
  }
}
...
<!-- 将工厂类进行ioc配置 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>

<!-- 根据工厂对象的实例工厂方法进行实例化组件对象 -->
<bean id="clientService"
  factory-bean="serviceLocator"
  factory-method="createClientServiceInstance"/>
  • factory-bean属性:指定当前容器中工厂Bean 的名称。

  • factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的

 7.3组件(Bean)依赖注入

通过配置文件,实现IoC容器中Bean之间的引用(依赖注入DI配置)。

 7.3.1基于构造函数的依赖注入(单个构造函数)

  基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数表示一个依赖项。

组件类

public class UserDao {
}

public class UserService {
    private UserDao userDao;
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

 配置文件

<beans>
      <!-- 引用类bean声明 -->
      <bean id="userService" class="com.csi.service.impl.UserServiceImpl">
       <!-- 构造函数引用 -->
        <constructor-arg ref="userDao"/>
        <constructor-arg index="索引位置" name="参数名称" type="参数的类型" value="" ref=""/>
      </bean>
      <!-- 被引用类bean声明 -->
      <bean id="userDao" class="UserDao"/>
</beans>

7.3.2基于构造函数的依赖注入(多构造参数)

public class UserDao {
}
public class UserService {
    private UserDao userDao;        
    private int age;        
    private String name;

    public UserService(int age , String name ,UserDao userDao) {
        this.userDao = userDao;
        this.age = age;
        this.name = name;
    }
}

配置文件 

 1.多参数,可以按照相应构造函数的顺序注入数据

<beans>
<bean id="userService" class="com.csi.service.impl.UserServiceImpl">
    <!-- value直接注入基本类型值 -->
    <constructor-arg  value="18"/>
    <constructor-arg  value="admin"/>
    <constructor-arg  ref="userDao"/>
</bean>
<!-- 被引用类bean声明 -->
<bean id="userDao" class="com.csi.dao.impl.UserDaoImpl"/>
</beans>

 2.多参数,可以按照相应构造函数的名称注入数据

<beans>
<bean id="userService" class="com.csi.service.impl.UserServiceImpl">
    <!-- value直接注入基本类型值 -->
    <constructor-arg name="name" value="admin"/>
    <constructor-arg name="userDao" ref="userDao"/>
    <constructor-arg name="age"  value="18"/>
</bean>
<!-- 被引用类bean声明 -->
<bean id="userDao" class="com.csi.dao.impl.UserDaoImpl"/>
</beans>

3. 多参数,可以按照相应构造函数的角标注入数据 index从0开始 构造函数(0,1,2....)

<beans>
<bean id="userService" class="com.csi.service.impl.UserServiceImpl">
    <!-- value直接注入基本类型值 -->
    <constructor-arg index="1" value="admin"/>
    <constructor-arg index="2" ref="userDao"/>
    <constructor-arg index="0"  value="18"/>
</bean>
<!-- 被引用类bean声明 -->
<bean id="userDao" class="com.csi.dao.impl.UserDaoImpl"/>
</beans>

7.3.3基于Setter方法依赖注入

public class UserDaoImpl implements UserDao {
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public User login(String userCode, String password) {
        RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class);
        String sql = "select * from smbms_user where userCode=? and userPassword=?";
        User user = jdbcTemplate.queryForObject(sql,mapper, userCode, password);
        return user;
    }
}

public class UserServiceImpl implements UserService {
   private UserDao userDao;
    @Override
    public User login(String userCode, String password) {
        return userDao.login(userCode, password);
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

配置文件

    <bean id="userDao" class="com.csi.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/> <!-- 注入 JdbcTemplate -->
    </bean>
<!-- setter方法,注入基本数据类型userDao
       name = 属性名 value= 基本类型值
   -->
    <bean id="userService" class="com.csi.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
  • property标签: 可以给setter方法对应的属性赋值

  • property 标签: name属性代表set方法标识、ref代表引用bean的标识id、value属性代表基本属性值

8.jdbc.properties文件

jdbc.url=jdbc:mysql://localhost:3306/smbms
jdbc.driver=com.mysql.cj.jdbc.Driver
//数据库连接账户名
jdbc.username=root
//数据库连接密码
jdbc.password=102815

9.BaseController 

public class BaseController extends HttpServlet {

    private WebApplicationContext webCtx ;

    @Override
    public void init() throws ServletException {

       webCtx=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()) ;
    }

    public Object getBean(String id) {
        return webCtx.getBean(id) ;
    }
}

BaseController 继承自 HttpServlet,这意味着它是一个 Servlet,可以处理 HTTP 请求。

WebApplicationContext 的使用

WebApplicationContext 是 Spring 的一个上下文接口,它包含了 Spring 应用程序的所有信息,能够管理 Spring bean 的生命周期和依赖注入。

在 init() 方法中,使用 WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()) 获取当前 Servlet 上下文中的 WebApplicationContext 实例。这样,可以在 Servlet 中使用 Spring 管理的 bean。

getBean 方法

getBean(String id) 方法允许通过 bean 的 ID 从 Spring 容器中获取对应的 bean 实例。这使得在 Servlet 中能够方便地访问 Spring 管理的服务和组件。

注:使用tomcat10版本,存在版本的兼容性问题,介意使用tomcat9的版本

一.登录

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>系统登录 - 超市账单管理系统</title>
    <link type="text/css" rel="stylesheet" href="css/style.css"/>
    <script type="text/javascript" src="JQuery/jquery-1.11.3.min.js"></script>
    <style type="text/css">
        #login .hint {
            /* border: 1px solid red; */
            width: 120px;
            top: 120px;
            margin-left: 235px;
            margin-top: -70px;
            color: red;
        }
    </style>
    <%
        String type = (String) request.getAttribute("type");
    %>
</head>
<body class="blue-style">
<div id="login">
    <div class="icon"></div>
    <div class="login-box">
        <form id="loginForm">
            <dl>
                <dt>用户名:</dt>
                <dd><input type="text" name="userCode" class="input-text" id="userCode"/></dd>
                <dt>密 码:</dt>
                <dd><input type="password" name="passWord" class="input-text" id="password"/></dd>
            </dl>
            <div class="buttons">
                <input type="button" name="submit" value="登录系统" class="input-button" id="submitLogin"/>
                <input type="reset" name="reset" value="重  填" class="input-button"/>
            </div>
        </form>
    </div>
</div>

</body>
</html>

在登录时,先传入用户账号和密码,通过dao层向数据库中查找该用户信息,如果用户存在则返回用户信息并跳转到系统首页,如果用户不存在则提示无法登录。

登录页面AJAX请求

<script type="text/javascript">
    $(function () {
        $("#submitLogin").click(function (event) {
            event.preventDefault(); // 阻止默认提交
            var subUserCode = $("#userCode").val();//获取输入的登录账户
            var password = $("#password").val();//获取输入的登录密码

            $.post("http://localhost:8080/smbms/LoginController",//发起AJAX请求
                {userCode: subUserCode, pass: password},
                function (loginResult) {
                    if (loginResult.code === 200) {
                        // 登录成功,重定向到主页面
                        location.href = "http://localhost:8080/smbms/admin_index.html";
                    } else {
                        // 登录失败,显示错误提示
                        alert("账号或密码错误!")
                        location.href = "http://localhost:8080/smbms/login.jsp";
                    }
                },
                "json" // 指定返回的数据类型为 JSON
            )
        });
    });
</script>

User类

@Getter
@Setter
public class User {
    private long id;
    private String userCode;
    private String userName;
    private String userPassword;
    private int gender;
    private Date birthday;
    private String phone;
    private String address;
    private long userRole;
    private Long createBy;
    private Date creationDate;
    private Long modifyBy;
    private Date modifyDate;
    public User(String userCode, String userPassword) {
        this.userCode = userCode;
        this.userPassword = userPassword;
    }
    public User() {
    }

}

UserDaoImpl代码

public class UserDaoImpl implements UserDao {
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public User login(String userCode, String password) {
        RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class);
        String sql = "select * from smbms_user where userCode=? and userPassword=?";
        User user = jdbcTemplate.queryForObject(sql,mapper, userCode, password);
        return user;
    }
}

 UserServiceImpl代码

public class UserServiceImpl implements UserService {
   private UserDao userDao;
    @Override
    public User login(String userCode, String password) {
        return userDao.login(userCode, password);
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

UserDaoImpl测试类1

public class LoginTest {
    @Test
    public void testLogin() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
        RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class);
        String sql = "select * from smbms_user where userCode=? and userPassword=?";
        User user = jdbcTemplate.queryForObject(sql, mapper, "admin", "1");

        System.out.println(user);
    }
}

问题分析:出现了 org.springframework.beans.TypeMismatchException 异常,提示无法将 null 值转换为基本类型 long

原因,在创建User对象时,user对象拥有的字段中有包含数据类型为long型的字段,而数据库中该字段的内容为null,在 Java 中,基本类型(如 long, int 等)不能接受 null 值,而包装类型(如 Long, Integer 等)可以。因此,如果 User 类中的 某一属性是 long 类型,而数据库查询结果中该字段的值为 null,就会导致转换失败。

解决方法:将user对象中的long类型改为Long包装类型。

UserDaoImpl测试类2

 @Test
public void testLogin() {
   UserDao userDao = new UserDaoImpl();
   User user = userDao.login("admin", "1");
   System.out.println(user);
}

报错点:提示无法调用 org.springframework.jdbc.core.JdbcTemplate.queryForObject,因为 this.jdbcTemplatenull。这个问题的根本原因是 JdbcTemplate 实例未被正确注入到 UserDaoImpl

问题分析:

  1. 未注入 JdbcTemplate:在 UserDaoImpl 类中,jdbcTemplate 变量是一个依赖项,它需要通过 Spring 容器进行注入。如果在创建 UserDaoImpl 实例时没有设置 JdbcTemplate,则会导致 jdbcTemplatenull,从而在调用 queryForObject 方法时抛出 NullPointerException

  2. 测试方法中的实例化:在 testLogin 方法中,直接通过 new UserDaoImpl() 创建了 UserDaoImpl 的实例,但没有调用 setJdbcTemplate 方法来注入 JdbcTemplate 实例。

解决方法:在测试方法中,需要确保 UserDaoImpl 是通过 Spring 容器获取的,而不是直接通过 new 关键字创建的

UserDaoImpl测试类2正确测试代码:

    @Test
    public void testLogin() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) context.getBean("userDao"); // 从 Spring 容器获取 UserDao 实例
        User user = userDao.login("admin", "1");
        System.out.println(user);
    }

LoginController代码

继承BaseController,直接在代码中通过 id 从 Spring 容器中获取 bean

@WebServlet("/LoginController")
public class LoginController extends BaseController{

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("application/json;charset=utf-8");

        String userCode = req.getParameter("userCode");
        String pass = req.getParameter("pass");

        UserService userService = (UserService) getBean("userService");
        User user = userService.login(userCode, pass);

        Result<User> loginResult=null;
        if(user != null){
            HttpSession session = req.getSession();
            session.setAttribute("userinfo", user);
            System.out.println(user);
            loginResult=new Result<>("登录成功",200);
            loginResult.setData(user);

        }else if (user==null){
            loginResult=new Result<>("登录失败",300);
        }

        String json = JSON.toJSONString(loginResult);
        PrintWriter out = resp.getWriter();
        out.print(json);
        out.close();

    }
}

登录成功则跳转页面

如果用户密码与账号不匹配,则不进行跳转,直接返回登录页面,在测试时,遇到以下错误,这是因为如果没有找到相关用户的记录,查询将返回 0 行,从而导致 EmptyResultDataAccessException 异常。

如果希望在没有找到用户时不抛出异常,可以在 login 方法中使用 try-catch 块捕获 EmptyResultDataAccessException

修改dao层的代码如下

@Override
    public User login(String userCode, String password) {

        RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class);
        String sql = "select * from smbms_user where userCode=? and userPassword=?";
        User user =null;
        try {
            user = jdbcTemplate.queryForObject(sql,mapper, userCode, password);
            return user;
        }catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

首页头部

 在进行登录时,设置了session,将登录查找到的用户信息通过session.setAttribute("userinfo", user);存入session中,在首页直接通过request.getSession().getAttribute("userinfo")获取到用户信息,并显示在头部

 admin_top.jsp

<%@ page import="com.csi.domain.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<link type="text/css" rel="stylesheet" href="css/style.css" />
	<script type="text/javascript" src="JQuery/jquery-1.11.3.min.js"></script>
	<%
		User userinfo = (User) request.getSession().getAttribute("userinfo");
	%>
</head>
<body>
<div id="header">
	<div class="title"></div>
	<div class="welcome">欢迎您:<%=userinfo.getUserName()%></div>
	<div class="welcome"></div>
</div>
</body>

</html>

二.账单管理

admin_bill_list.jsp

<%@ page import="com.csi.domain.Provider" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.csi.domain.Order" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link type="text/css" rel="stylesheet" href="css/style.css"/>
    <style>
        <%--		分页样式--%>
        .content .list a, .content .list a:visited {
            text-decoration: none;
            color: white;
            width: 15px;
            height: 10px;
            background-color: #92d1f4;
            /*margin-right: 2px;*/
            border-radius: 2px;
        }

        .content .list {
            display: inline-block;
            vertical-align: middle;
        }

        .page-wrap {
            /*border: 1px solid black;*/
            margin-top: 100px;
            margin-left: 550px;
        }

        .page {
            text-decoration: none;
            border: 1px solid #92d1f4;
            padding: 2px 4px;
            margin-right: 2px;
            margin-left: 2px;
            color: black;
        }
    </style>
    <%
        List<Order> orders = (List<Order>) session.getAttribute("orderList");

        int totalCount = (int) session.getAttribute("totalCount"); //总条数
        int pageSize = (int) session.getAttribute("pageSize"); //每页显示条数
        int totalPageNo = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1; //一共多少页
        int pageNum = (int) session.getAttribute("pageNum"); //当前页
        int reviewPageNO = pageNum <= 1 ? reviewPageNO = 1 : pageNum - 1; //计算上一页的页码
        int nextPageNo = pageNum >= totalPageNo ? nextPageNo = totalPageNo : pageNum + 1; //计算下一页页码

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    %>
</head>
<body>
<div class="menu">
    <form method="get" action="<%=request.getContextPath()%>/FindOrderByCondition">
        商品名称:<input type="text" name="productName" class="input-text"/>&nbsp;&nbsp;&nbsp;&nbsp;
        供应商名称:<select name="providerId">
        <option value="-1">请选择</option>
        <option value="></option>
    </select>&nbsp;&nbsp;&nbsp;&nbsp;
        是否付款:<select name="payStatus">
        <option value="-1">请选择</option>
        <option value="1">已付款</option>
        <option value="2">未付款</option>
    </select>&nbsp;&nbsp;&nbsp;&nbsp;
        <input type="submit" name="submit" value="组合查询" class="button"/>
    </form>
</div>
<div class="main">
    <div class="optitle clearfix">
        <em><input type="button" name="button" value="添加数据" class="input-button" style="margin-left: 20px"
                   onclick="location.href='orderAdd.jsp'"/></em>
        <em><input type="button" name="button" value="批量删除" class="input-button" onclick="deleteMore()"/></em>
        <div class="title">账单管理&gt;&gt;</div>
    </div>
    <div class="content">
        <table class="list">
            <tr>
                <td style="width: 60px">
                    <form id="deleteAll" action="<%=request.getContextPath()%>/DeleteOrderController" method="get"
                          style="display: inline-block">
                        <input type="checkbox" id="allCheck" name="allCheck" onclick="choiceAll()" value="on"/>全选
                    </form>
                </td>
                <td>账单编号</td>
                <td style="width: 60px">商品名称</td>
                <td style="width: 60px">商品数量</td>
                <td style="width: 60px">交易金额</td>
                <td style="width: 60px">是否付款</td>
                <td style="width: 120px;">供应商名称</td>
                <td style="width: 100px;">商品描述</td>
                <td>账单时间</td>
                <td style="width: 120px;">操&nbsp;&nbsp;作</td>
            </tr>
            <form id="deleteForm" action="<%=request.getContextPath()%>/DeleteOrderController" method="post">
                <div>
                    <%
                        if (orders == null || orders.size() == 0) {
                            String tishi = "当前没有该账单信息!";
                    %>
                    <%=tishi%>
                    <%
                    } else {
                        for (Order order : orders) {
                    %>
                    <tr>
                        <td><input id="checkOn" name="checkOn" type="checkbox" value="<%=order.getId()%>"
                                   style="display: inline-block;vertical-align: middle"/></td>
                        <td><%=order.getBillCode()%>
                        </td>
                        <td><%=order.getProductName()%>
                        </td>
                        <td><%=order.getProductCount()%>
                        </td>
                        <td><%=order.getTotalPrice()%>
                        </td>
                        <td>
                            <%
                                if (order.getIsPayment() == 1) {
                            %>
                            <span>未支付</span>
                            <%
                            } else if (order.getIsPayment() == 2) {
                            %>
                            <span>已支付</span>
                            <%
                                }
                            %>
                        </td>
                        <td><%=order.getProvider().getProName()%>
                        </td>
                        <td><%=order.getProductDesc()%>
                        </td>
                        <td>
                            <%
                                String time = sdf.format(order.getCreationDate());
                            %>
                            <%=time%>
                        </td>
                        <td>
                            <a class="caozuo"
                               href="<%=request.getContextPath()%>/orderModify.jsp?billCode=<%=order.getBillCode()%>&productName=<%=order.getProductName()%>">修改</a>
                            <a class="caozuo" onclick="return confirm('确定删除吗?')"
                               href="<%=request.getContextPath()%>//DeleteController?billCode=<%=order.getBillCode()%>">删除</a>
                            <a class="caozuo" href="#">详情</a>
                        </td>
                    </tr>
                    <%
                            }
                        }
                    %>
                </div>
            </form>
        </table>
    </div>

    <div class="page-wrap">
        <a href="<%=request.getContextPath()%>/OrderListController?pageNum=<%=reviewPageNO%>&pageSize=<%=pageSize%>"
           class="pagePre page">上一页</a>
        <%
            for (int i = 1; i <= totalPageNo; i++) {
        %>
        <a href="<%=request.getContextPath()%>/OrderListController?pageNum=<%=i%>&pageSize=<%=pageSize%>"
           class="page pageNo"><%=i%>
        </a>
        <%
            }
        %>
        <a href="<%=request.getContextPath()%>/OrderListController?pageNum=<%=nextPageNo%>&pageSize=<%=pageSize%>"
           class="pageNext page">下一页</a>
    </div>
</div>
<script type="text/javascript">
    function deleteMore() {
        if (confirm("确定要删除选中的订单吗?")) {
            document.getElementById("deleteForm").submit();
        }
    }
</script>
</body>
</html>

2.1 账单管理-账单信息显示

在applicationContext.xml中加入dao与jabcTemplate对象的关系

<bean id="orderDao" class="com.csi.dao.impl.OrderDaoImpl">
   <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="orderService" class="com.csi.service.impl.OrderServiceImpl">
   <property name="orderDao" ref="orderDao"/>
</bean>

 Order类

@Setter
@Getter
public class Order {
    private long id;
    private String billCode;
    private String productName;
    private String productDesc;
    private String productUnit;
    private double productCount;
    private double totalPrice;
    private int isPayment;
    private Long   createdBy;
    private Date creationDate;
    private Long   modifyBy;
    private Date   modifyDate;
    private long providerId;
    private Provider provider ;
}

OrderRowMapper类 

public class OrderRowMapper implements RowMapper<Order> {
    @Override
    public Order mapRow(ResultSet rs, int rowNum) throws SQLException {
        Order order = new Order();
        order.setId(rs.getLong("id"));
        order.setBillCode(rs.getString("billCode"));
        order.setProductName(rs.getString("productName"));
        order.setProductDesc(rs.getString("productDesc"));
        order.setProductUnit(rs.getString("productUnit"));
        order.setProductCount(rs.getDouble("productCount"));
        order.setTotalPrice(rs.getDouble("totalPrice"));
        order.setIsPayment(rs.getInt("isPayment"));
        order.setCreatedBy(rs.getLong("createdBy"));
        order.setCreationDate(rs.getDate("creationDate"));
        order.setModifyBy(rs.getLong("modifyBy"));
        order.setModifyDate(rs.getDate("modifyDate"));
        order.setProviderId(rs.getLong("providerId"));

        // 初始化 Provider 对象,在查找order数据时,provider字段需要什么信息则保留什么信息
        Provider provider = new Provider();
//        provider.setId(rs.getLong("p.id")); // 确保列名正确
//        provider.setProCode(rs.getString("p.proCode"));
        provider.setProName(rs.getString("p.proName"));
        provider.setProDesc(rs.getString("p.proDesc"));
//        provider.setProContact(rs.getString("p.proContact"));
//        provider.setProPhone(rs.getString("p.proPhone"));
//        provider.setProAddress(rs.getString("p.proAddress"));
//        provider.setProFax(rs.getString("p.proFax"));
//        provider.setCreatedBy(rs.getLong("p.createdBy"));
//        provider.setCreationDate(rs.getDate("p.creationDate"));
//        provider.setModifyBy(rs.getLong("p.modifyBy"));
//        provider.setModifyDate(rs.getDate("p.modifyDate"));

        order.setProvider(provider); // 将 Provider 设置到 Order 中

        return order;
    }
}

OrderDaoImpl代码

public class OrderDaoImpl implements OrderDao {
    private JdbcTemplate jdbcTemplate;
     @Override
    public List<Order> list() {
        String sql = "SELECT b.*, p.* FROM smbms_bill b JOIN smbms_provider p ON b.providerId = p.id LIMIT ? OFFSET ?";
        int offset = (pageNum - 1) * pageSize;//表示从哪一条记录开始返回数据
        //new Object[]{pageSize, offset},对象数组,包含 SQL 查询中需要绑定的参数
        // pageSize:表示每页显示的记录数。
        return jdbcTemplate.query(sql, new Object[]{pageSize, offset}, new OrderRowMapper());
    }
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

OrderServicImpl代码

public class OrderServiceImpl implements OrderService {
    private OrderDaoImpl orderDao;
    @Override
    public List<Order> list() {
        return orderDao.list();
    }
    public void setOrderDao(OrderDaoImpl orderDao) {
        this.orderDao = orderDao;
    }
}

OrderDaoImpl-list测试类

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao = (OrderDao) context.getBean("orderDao");
        List<Order> orderList = orderDao.list();
        System.out.println(orderList);
    }

    @Test public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       OrderService orderService= (OrderService) context.getBean("orderService");
        List<Order> orderList = orderService.list();
        System.out.println(orderList);
    }

报错点:这个错误提示表明尝试访问 Provider 对象的 getProName() 方法,但 Provider 对象本身是 null。是因为在创建 Order 对象时,没有正确地初始化 provider 属性。

 解决办法:确保SQL 查询能够正确地联接 smbms_billsmbms_provider 表,并且在结果集中返回了 Provider 的所有必要字段。确保 providerIdsmbms_bill 表中有相应的值,并且可以在 smbms_provider 表中找到对应的记录。

确保在查询结果映射时,正确地将 Provider 对象初始化到 Order 对象中。通过自定义 RowMapper 来处理这个映射(OrderRowMapper类),然后在 OrderDaoImpl 中使用这个 RowMapper

报错点:在进行数据查找时,根据OrderDao层中对返回的List数据来看,对于provider表查出来的数据只显示proName和proDesc,那么在设置需要什么则设置什么,如果全部打开则会报错 

解决办法一:在OrderRowMapper类中只给Provider对象设置proName和proDesc

解决办法二:将OrderDao层的sql代码中对provider查找全部,并在OrderRowMapper类中给Provider对象设置全部字段信息或者设置需要的字段

 OrderListController代码

 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过getBean方法,获取到ioc容器中的对象
        int pageNum = req.getParameter("pageNum") == null ? 1 : Integer.parseInt(req.getParameter("pageNum"));
        int pageSize = req.getParameter("pageSize") == null ? 5 : Integer.parseInt(req.getParameter("pageSize"));

        PageHelper.startPage(pageNum,pageSize) ;

       OrderService orderService = (OrderService) getBean("orderService");
        List<Order> orderList = orderService.list();
        int totalCount = orderService.totalCount();

        HttpSession session = req.getSession();
        session.setAttribute("totalCount",totalCount);
        session.setAttribute("pageSize",pageSize);
        session.setAttribute("pageNum",pageNum);
        session.setAttribute("orderList",orderList);

        resp.sendRedirect(req.getContextPath() + "/admin_bill_list.jsp");
    }

详情列表分页

问题:分页不能正确显示(该分页使用PageHelper)

OrderListController层获取页码数及每页显示条数传入PageHelper

OrderDaoImpl层中从数据库查找总记录数

@Override
    public int totalCount() {
        String sql = "select count(*) from smbms_bill";
        int totalCount = jdbcTemplate.queryForObject(sql, Integer.class);
        return totalCount;
    }

在页面中渲染分页

报错点:在OrderDaoImpl层中的查询没有实现分页,需要在 SQL 查询中添加 LIMITOFFSET 子句,以便根据当前页码和每页大小限制结果集。 

解决方案:

修改 OrderDaoImpllist() 方法以支持分页: 更新 SQL 查询以使用分页。您可以在 SQL 查询中添加 LIMITOFFSET

@Override
    public List<Order> list(int pageNum, int pageSize) {
        String sql = "SELECT b.*, p.* FROM smbms_bill b JOIN smbms_provider p ON b.providerId = p.id LIMIT ? OFFSET ?";
        int offset = (pageNum - 1) * pageSize;
        return jdbcTemplate.query(sql, new Object[]{pageSize, offset}, new OrderRowMapper());
    }

 更新 OrderServicelist() 方法: 确保在 OrderService 中的 list() 方法接受 pageNumpageSize 参数,并将它们传递给 DAO 层

@Override
    public List<Order> list(int pageNum, int pageSize) {
        return orderDao.list(pageNum, pageSize);
    }

分页效果显示 

2.2 账单管理-账单信息增加 

 当用户点击添加数据,则跳转到新增页面,通过getParameter()方法拿回每个参数的值,并调用OrderServiceImpl的save()方法实现数据的增加,保存成功后重新跳转到账单列表页面,并刷新数据

OrderDaoImpl代码

jdbcTemplate.update(sql, ...) 用于执行更新操作(包括插入、更新和删除)。它会返回受影响的行数。 

@Override
    public int save(Order order) {
        String sql = "INSERT INTO smbms_bill (billCode, productName, productDesc, productUnit, productCount, " +
                "totalPrice, isPayment, createdBy, creationDate, providerId) " +
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        // 使用 jdbcTemplate 执行插入操作
     int save=jdbcTemplate.update(sql,
                order.getBillCode(),          // 账单编号
                order.getProductName(),       // 商品名称
                order.getProductDesc(),       // 商品描述
                order.getProductUnit(),       // 商品单位
                order.getProductCount(),      // 商品数量
                order.getTotalPrice(),        // 交易金额
                order.getIsPayment(),         // 是否付款
                order.getCreatedBy(),         // 创建者
                order.getCreationDate(), // 创建时间
                order.getProviderId()         // 供应商ID
        );
        return save;
    }

 OrderServiceImpl代码

@Override
    public int save(Order order) {
        return orderDao.save(order);
    }

AddOrderController代码

每个controller都需要继承BaseController

@WebServlet("/AddOrderController")
public class AddOrderController extends BaseController {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

//获取数据
        Order order = new Order();
        order.setBillCode(req.getParameter("billCode"));
        order.setProductName(req.getParameter("productName"));
        order.setProductDesc(req.getParameter("productDesc"));
        order.setProductCount(Double.parseDouble(req.getParameter("productCount")));
        order.setProductUnit(req.getParameter("productUnit"));
        order.setTotalPrice(Double.parseDouble(req.getParameter("totalPrice")));
        order.setProviderId(Long.parseLong(req.getParameter("providerId")));
        order.setIsPayment(Integer.parseInt(req.getParameter("isPay")));
        order.setCreatedBy(Long.parseLong(req.getParameter("createdBy")));
        order.setCreationDate(new Date());

//获取getBean
        OrderService orderService = (OrderService) getBean("orderService");
        int save = orderService.save(order);

//转发到账单列表页面
        req.getRequestDispatcher("/OrderListController").forward(req, resp);
    }
}

OrderAdd.jsp

隐藏域表单,用来获取创建者和创建时间,创建者身份通过request.getSession().getAttribute("userinfo")直接获取

<%@ page import="com.csi.domain.User" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link type="text/css" rel="stylesheet" href="css/style.css"/>
    <%
        User userinfo = (User) request.getSession().getAttribute("userinfo");
    %>
</head>
<body>
<div class="menu">
    <form method="post" action="<%=request.getContextPath()%>/FindOrderByCondition" onsubmit="return checkit();">
        商品名称:<input type="text" name="productName" class="input-text"/>&nbsp;&nbsp;&nbsp;&nbsp;
        是否付款:<select name="payStatus">
        <option value="">请选择</option>
        <option value="1">已付款</option>
        <option value="0">未付款</option>
    </select>&nbsp;&nbsp;&nbsp;&nbsp;
        <input type="submit" name="submit" value="组合查询" class="button"/>
    </form>
</div>
<div class="main">
    <div class="optitle clearfix">
        <em><input type="button" name="button" value="添加数据" class="input-button"
                   onclick="location.href='modify.html'"/></em>
        <div class="title">账单管理&gt;&gt;</div>
    </div>
    <form method="post" action="<%=request.getContextPath()%>/AddOrderController">
        <div class="content">
            <table class="box">
                <tr>
                    <td class="field">账单编号:</td>
                    <td><input type="text" name="billCode" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">商品名称:</td>
                    <td><input type="text" name="productName" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">商品描述:</td>
                    <td><textarea name="productDesc"></textarea></td>
                </tr>
                <tr>
                    <td class="field">交易数量:</td>
                    <td><input type="text" name="productCount" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">商品单位:</td>
                    <td><input type="text" name="productUnit" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">交易金额:</td>
                    <td><input type="text" name="totalPrice" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">供应商ID:</td>
                    <td><input type="text" name="providerId" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">是否付款:</td>
                    <td><select name="isPay">
                        <option value="-1">请选择</option>
                        <option value="1">已付款</option>
                        <option value="2">未付款</option>
                    </select></td>
                </tr>
//隐藏域表单,用来获取创建者和创建时间,创建者身份通过request.getSession().getAttribute("userinfo")直接获取
                <input name="createdBy" value="<%=userinfo.getUserRole()%>" class="text" type="hidden">
                <input name="creationDate" value="<%=new Date()%>" class="text" type="hidden">
            </table>
        </div>
        <div class="buttons">
            <input type="submit" name="submit" value="确认" class="input-button" onclick="add()"/>
            <input type="button" name="button" value="返回" class="input-button" onclick="history.back();"/>
        </div>
    </form>
</div>
<script>
    function add(){
        alert("添加成功!")
    }
</script>
</body>
</html>

2.3 账单管理-账单信息删除 

用户点击删除按钮,弹出提示“是否要删除”,如果是则将账单编号传入后台,调用delete()方法删除该数据,删除成功后刷新数据并跳转回账单列表页面

新增dao代码

@Override
    public int delete(String billCode) {
        String sql = "delete from smbms_bill where billCode=?";
    //直接传入sql语句以及账单编号
        int delete = jdbcTemplate.update(sql, billCode);
        return delete;
    }

 新增service代码

@Override
    public int delete(String billCode) {
        return orderDao.delete(billCode);
    }

DeleteController代码

@WebServlet("/DeleteController")
public class DeleteController extends BaseController {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        OrderService orderService = (OrderService) getBean("orderService");
        String billCode = req.getParameter("billCode");
        orderService.delete(billCode);

        req.getRequestDispatcher("/OrderListController").forward(req, resp);
    }
}

在jsp页面中需要调用该DeleteController

为删除添加一个点击事件,为ture则删除,为false则返回。

 2.4 账单管理-账单信息修改

 当用户点击修改,则跳转到新增页面,通过getParameter()方法拿回每个参数的值,并调用OrderServiceImpl的update()方法实现数据的增加,保存成功后重新跳转到账单列表页面,并刷新数据

前端页面传值时,将商品名称及商品编号一并传回,修改表单显示时则会将商品名称及商品编号选软到页面中。

OrderModify.jsp

<%@ page import="com.csi.domain.User" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link type="text/css" rel="stylesheet" href="css/style.css"/>
    <%
        User userinfo = (User) request.getSession().getAttribute("userinfo");
        String billCode = request.getParameter("billCode");
        String productName = request.getParameter("productName");
    %>
</head>
<body>
<div class="menu">
    <form method="post" action="<%=request.getContextPath()%>/FindOrderByCondition" onsubmit="return checkit();">
        商品名称:<input type="text" name="productName" class="input-text"/>&nbsp;&nbsp;&nbsp;&nbsp;
        是否付款:<select name="payStatus">
        <option value="">请选择</option>
        <option value="1">已付款</option>
        <option value="0">未付款</option>
    </select>&nbsp;&nbsp;&nbsp;&nbsp;
        <input type="submit" name="submit" value="组合查询" class="button"/>
    </form>
</div>
<div class="main">
    <div class="optitle clearfix">
        <em><input type="button" name="button" value="添加数据" class="input-button"
                   onclick="location.href='orderModify.jsp'"/></em>
        <div class="title">账单管理&gt;&gt;</div>
    </div>
    <form method="post" action="<%=request.getContextPath()%>/ModifyOrderController">
        <div class="content">
            <table class="box">
                <tr>
                    <td class="field">账单编号:</td>
                    <td><input type="text" name="billCode" class="text" readonly value="<%=billCode%>"/></td>
                </tr>
                <tr>
                    <td class="field">商品名称:</td>
                    <td><input type="text" name="productName" class="text" value="<%=productName%>"/></td>
                </tr>
                <tr>
                    <td class="field">商品描述:</td>
                    <td><textarea name="productDesc"></textarea></td>
                </tr>
                <tr>
                    <td class="field">交易数量:</td>
                    <td><input type="text" name="productCount" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">商品单位:</td>
                    <td><input type="text" name="productUnit" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">交易金额:</td>
                    <td><input type="text" name="totalPrice" class="text"/></td>
                </tr>
                <tr>
                    <td class="field">是否付款:</td>
                    <td><select name="isPay">
                        <option value="-1">请选择</option>
                        <option value="1">已付款</option>
                        <option value="2">未付款</option>
                    </select></td>
                </tr>
                <input name="modifyBy" value="<%=userinfo.getUserRole()%>" class="text" type="hidden">
                <input name="modifyDate" value="<%=new Date()%>" class="text" type="hidden">
            </table>
        </div>
        <div class="buttons">
            <input type="submit" name="submit" value="确认" class="input-button" onclick="modify()"/>
            <input type="button" name="button" value="返回" class="input-button" onclick="history.back();"/>
        </div>
    </form>
</div>
<script>
    function modify(){
        alert("修改成功!")
    }
</script>
</body>
</html>

修改成功后跳转到账单列表显示页面,修改结果同步刷新到页面

报错点

异常类型:

TransientDataAccessResourceException 表示在访问数据资源时发生了瞬时的异常,通常是由于参数传递不正确导致的。

SQL 语句:

 SQL 更新语句中定义了 9 个参数(productNameproductDescproductUnitproductCounttotalPriceisPaymentmodifyBymodifyDatebillCode),但在执行时却提示参数索引超出范围,表明在传递参数时出现了问题。

参数索引超出范围:

异常信息中提到的“Parameter index out of range (10 > number of parameters, which is 9)”意味着在您的代码中,尝试访问第 10 个参数,但实际上只提供了 9 个参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值