10.Spring Boot 实战~Spring Boot总结 ( 增,删,查,改,上传,分页 )

10.Spring Boot 实战~Spring Boot总结 ( 增,删,查,改,上传,分页 )

本文是上一篇文章的后续,详情点击该链接~

项目需求

增,删,查,改,上传,分页

在这里插入图片描述

项目准备

搭建项目结构

在这里插入图片描述

导入依赖

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

    <!-- spring-boot-starter-parent继承spring-boot-dependencies
         定义若干plugin,可以在子工程中直接使用。
         如: spring-boot-maven-plugin的打包机制
         如: maven-compiler-plugin的参数自动补全机制
     -->
    <!--<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
    </parent>-->

    <groupId>com.alvin</groupId>
    <artifactId>test_framework</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencyManagement>
        <!-- 只定义了spring-boot的核心依赖资源版本,没有插件的定义
             如果需要打包,必须自定义spring-boot-maven-plugin的executions
             好处是,不需要让商业项目继承spring的开源项目。
         -->
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.13</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <parameters>true</parameters>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>repackage</id>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml配置文件

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_framework?serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  thymeleaf:
    prefix: classpath:/myviews/  # thymeleaf返回结果的视图前缀。默认 classpath:/templates/
    suffix: .html # thymeleaf返回结果视图后缀,默认 .html
mybatis:
  mapper-locations: classpath:/mybatisxml/**/*.xml

数据库

create database test_framework;

use test_framework;

drop table if exists tb_customer;

create table tb_customer(
  id integer not null auto_increment,
  name varchar(32) comment '姓名',
  gender varchar(8) comment '性别',
  age int(3) comment '年龄',
  img varchar(64) comment '头像文件路径及文件名',
  orig_img varchar(64) comment '客户上传的头像文件原始命名',
  primary key(id)
);

drop table if exists tb_phone;

create table tb_phone(
  id integer not null auto_increment,
  phone_no varchar(18) comment '联系方式',
  customer_id integer comment '客户主键',
  primary key (id)
);

INSERT INTO tb_customer VALUES (1, '李子明', '男', 20, '/imgs/1.jpg', '1.jpg');
INSERT INTO tb_customer VALUES (2, '赵天', '男', 24, '/imgs/2.jpg', '2.jpg');
INSERT INTO tb_customer VALUES (3, '王羽', '男', 18, '/imgs/3.jpg', '3.jpg');
INSERT INTO tb_customer VALUES (4, '赵珊', '女', 23, '/imgs/4.jpg', '4.jpg');
INSERT INTO tb_customer VALUES (5, '刘海信', '男', 66, '/imgs/7.jpg', '7.jpg');
INSERT INTO tb_customer VALUES (6, '陈天一', '女', 21, '/imgs/5.jpg', '5.jpg');
INSERT INTO tb_customer VALUES (8, '黄贵根', '男', 19, '/imgs/f4d1847c-16ea-413f-a3eb-fa7b2c2d1750.png', 'timg.png');

后台代码

CustomerController

package com.alvin.controller;

import com.alvin.pojo.Customer;
import com.alvin.pojo.Phone;
import com.alvin.service.CustomerService;
import com.alvin.service.PhoneService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.util.Map;


@Controller
public class CustomerController {
    @Autowired
    private CustomerService customerService;
    @Autowired
    private PhoneService phoneService;

    /**
     * 删除客户,需要先删除客户的所有联系方式。再删除客户。
     * @param id
     * @return
     */
    @RequestMapping("/removeCustomer")
    public String removeCustomer(Integer id){
        boolean isRemoved = customerService.removeCustomer(id);
        if(isRemoved){
            return "redirect:/";
        }
        // 删除失败
        return "redirect:/toError";
    }

    /**
     * 修改客户资料
     * @param customer 客户新数据
     * @param uploadImg 修改的头像
     * @return
     */
    @RequestMapping("/modifyCustomer")
    public String modifyConsumer(Customer customer, MultipartFile uploadImg){
        boolean isModified = customerService.modifyCustomer(customer, uploadImg);
        if(isModified) {
            return "redirect:/showCustomer?id=" + customer.getId();
        }
        return "redirect:/toError";
    }

    @RequestMapping("/toModifyCustomer")
    public String toModifyCustomer(Integer id, Model model){
        Customer customer = customerService.getCustomerById(id);
        model.addAttribute("customer", customer);
        return "modifyCustomer";
    }

    /**
     * 新增联系方式
     * @param phone
     * @return
     */
    @RequestMapping("/addPhone")
    public String addPhone(Phone phone){
        boolean isAdded = phoneService.addPhone(phone);

        if(isAdded) {
            // 新增成功后的返回
            return "redirect:/showCustomer?id=" + phone.getCustomerId();
        }

        // 新增失败
        return "redirect:/toError";
    }

    /**
     * 跳转到新增联系方式
     * @param customerId 客户主键
     * @return
     */
    @RequestMapping("/toAddPhone")
    public String toAddPhone(Integer customerId, Model model){
        model.addAttribute("customerId", customerId);
        return "addPhone";
    }

    /**
     * 根据主键查询客户。并显示
     * 查询客户,及客户的联系方式集合。
     * @param id
     * @return
     */
    @RequestMapping("/showCustomer")
    public String showCustomer(Integer id, Model model){

        Customer customer = customerService.getCustomerById(id);

        model.addAttribute("customer", customer);

        return "showCustomer";
    }

    /**
     * 新增客户
     * PostMapping = @RequestMapping(method=RequestMethod.POST)
     *
     * MultipartFile - 使用文件上传处理的时候,商业开发中推荐增加注解@RequestParam,描述请求参数命名。
     *   减少程序员反复比对页面和代码之间的映射。
     *
     * 幂等性操作 - 反复执行对结果无影响。如,查询。
     * 非幂等性操作 - 反复执行,对结果有影响。如:增、删、改。
     * @return
     */
    @PostMapping("/addCustomer")
    public String addCustomer(Customer customer, MultipartFile uploadImg){

        boolean isAdded = customerService.addCustomer(customer, uploadImg);

        if(isAdded){
            // 新增成功。跳转到入口,重定向。避免刷新重复提交表单。
            // 商业开发中,所有的非幂等性操作,返回视图必须重定向。
            return "redirect:/";
        }

        // 新增失败,跳转到错误提示
        return "redirect:/toError";
    }

    // 不能使用路径 /error。 spring-boot-starter-web中内置的系统路径。
    @RequestMapping("/toError")
    public String toError(){
        return "error";
    }

    // 跳转到新增客户页面
    @RequestMapping("/toAddCustomer")
    public String toAddCustomer(){
        return "addCustomer";
    }

    // 入口, 分页查询客户
    @RequestMapping(value = {"/", "/index", "/default", "/welcome"})
    public String toIndex(Model model,
                          @RequestParam(value = "page", defaultValue = "1") int page,
                          @RequestParam(value = "rows", defaultValue = "5") int rows){
        Map<String, Object> map = customerService.getCustomersByPage(page, rows);
        model.addAllAttributes(map);
        return "index";
    }
}

CustomerMapper接口

package com.alvin.mapper;

import com.alvin.pojo.Customer;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface CustomerMapper {
    List<Customer> selectCustomers();

    int selectCount();

    int insert(Customer customer);

    Customer selectById(Integer id);

    int update(Customer customer);

    int deleteCustomer(Integer id);
}

PhoneMapper

package com.alvin.mapper;

import com.alvin.pojo.Phone;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface PhoneMapper {
    int insert(Phone phone);

    int deleteByCustomer(Integer id);
}

Customer

package com.alvin.pojo;

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

import java.io.Serializable;
import java.util.List;

/**
 * 企业开发规范中要求, 实体类型必须可序列化。必须私有化该私有的属性。必须为必要的属性提供getter和setter
 * 必须override方法hashCode和equals。必须提供至少一个无参构造方法。
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer implements Serializable {
    private Integer id;
    private String name;
    private String gender;
    private int age;
    private String img;
    private String origImg;
    private List<Phone> phoneList;
}

Phone

package com.alvin.pojo;

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

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Phone implements Serializable {
    private Integer id;
    private String phoneNo;
    private String customerId;
}

CustomerServiceImpl

package com.alvin.service.impl;

import com.alvin.mapper.CustomerMapper;
import com.alvin.mapper.PhoneMapper;
import com.alvin.pojo.Customer;
import com.alvin.service.CustomerService;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;

@Service
public class CustomerServiceImpl implements CustomerService {
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private PhoneMapper phoneMapper;

    /**
     * 先删除客户的所有联系方式。再删除客户
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean removeCustomer(Integer id) {
        // 删除联系方式
        phoneMapper.deleteByCustomer(id);
        int rows = customerMapper.deleteCustomer(id);
        if(rows != 1){
            throw new RuntimeException("删除客户失败");
        }
        return true;
    }

    /**
     * 修改客户数据
     * 判断上传的图片是否存在???
     * @param customer
     * @param uploadImg
     * @return
     */
    @Override
    @Transactional
    public boolean modifyCustomer(Customer customer, MultipartFile uploadImg) {
        String prefix = System.getProperty("user.dir") + File.separator + "src/main/resources/static/imgs/";
        try {
            // 判断上传的文件是否存在?
            int length = uploadImg.getInputStream().available();
            System.out.println("文件长度是:" + length + " 字节");
            if(length != 0){
                String origName = uploadImg.getOriginalFilename();
                // 更新了头像,需要重写头像数据, 查询原头像图片名,
                // 覆盖文件内容即可。 删除原头像图片,增加新的文件。
                Customer old = customerMapper.selectById(customer.getId());
                // 图片地址
                String img = prefix + old.getImg();
                File oldImg = new File(img);
                oldImg.delete();
                String tmpImg = UUID.randomUUID().toString() + origName.substring(origName.lastIndexOf("."));;
                String newImg = prefix + tmpImg;
                File newImgFile = new File(newImg);
                uploadImg.transferTo(newImgFile);

                // 把新的文件名称保存到客户对象中。
                customer.setImg("/imgs/"+tmpImg);
                customer.setOrigImg(origName);
            }

            int rows = customerMapper.update(customer);
            if(rows != 1){
                throw new RuntimeException("修改客户数据失败");
            }

        }catch (IOException e){
            e.printStackTrace();
        }

        return true;
    }

    /**
     * 主键查询客户
     * @param id
     * @return
     */
    @Override
    public Customer getCustomerById(Integer id) {
        return customerMapper.selectById(id);
    }

    /**
     * 新增客户。
     * 1、 保存数据到数据库
     * 2、 上传文件。 保存上传的文件到本地。
     *
     * Transactional - 控制事务
     *   propagation - 事务传播特性|传播行为,如何管理一个事务,如何在方法调用过程中管理一个事务。
     *     如: ma方法,要管理事务,如何控制?
     *     如: ma方法要管理事务,同时ma方法调用了mb方法,mb方法也要管理事务,如何控制?
     *     默认是required,必要事务。当前如果有事务,使用现有的,如果没有,创建新的。
     *     常用的supports,支持事务。当前如果有事务,使用现有的,如果没有,不创建事务。
     *   isolation - 事务隔离级别。 数据库事务有四大特性ACID。 spring事务管理中默认使用default。使用数据库隔离级别。
     *     原子性: 事务是原子的,不可分割的
     *     一致性: 数据一致的
     *     持久性: 数据是持久的
     *     隔离性: 多个事务之间,是隔离的。
     *       read_uncommitted - 读未提交,会有脏读现象。
     *       read_committed - 读已提交,会有不可重复读现象。oracle数据默认隔离级别
     *       repeatable_read - 可重复读,查询的时候,不提交事务,多次查询结果永久不变。开启事务,第一次查询
     *         保存结果到内存,后续未提交事务的所有查询,都直接返回内存结果。会有幻读现象。 是mysql的默认隔离级别。
     *       serializable - 串行化。数据库并行转串行。任何一个事务未提交之前,其他操作挂起阻塞。
     *   rollbackFor - 当什么类型的异常出现时,回滚事务。默认值是RuntimeException.class
     *
     * MyBatis默认事务管理行为是rollback还是commit?
     *   默认回滚。SqlSession的行为。在close的时候,如果发现有未完成的事务,自动回滚。
     *   未管理的事务,一概回滚,保证数据无错。
     *
     * Spring+MyBatis 默认事务管理行为是commit。
     *
     * @param customer
     * @param uploadImg
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = {RuntimeException.class})
    public boolean addCustomer(Customer customer, MultipartFile uploadImg) {
        try {
            // 找到 resources/static/imgs 文件夹
            String origImg = uploadImg.getOriginalFilename();
            String tmpName = UUID.randomUUID().toString() + origImg.substring(origImg.lastIndexOf("."));
            /*
             * System 对象。 系统对象。其中保存当前启动的JVM相关的所有信息
             *  getProperties - 当前启动的JVM进程相关信息
             *  getEnv - 当前启动的JVM的虚拟机相关信息。
             */
            Properties properties = System.getProperties();
            for(Map.Entry entry : properties.entrySet()){
                System.out.println(entry.getKey() + " --- " + entry.getValue());
            }
            System.out.println("====================================");
            Map<String, String> env = System.getenv();
            for(Map.Entry<String, String> entry: env.entrySet()){
                System.out.println(entry.getKey() + " - " + entry.getValue());
            }
            /*for(String key : env.keySet()){
                System.out.println(key + " - " + env.get(key));
            }*/
            String dir = System.getProperty("user.dir") + File.separator + "src/main/resources/static/imgs/";
            File file = new File(dir, tmpName);
            System.out.println(file.getAbsolutePath());
            // 保存文件到本地。
            uploadImg.transferTo(file);

            // 保存客户数据到数据库
            customer.setImg("/imgs/"+tmpName);
            customer.setOrigImg(origImg);

            int rows = customerMapper.insert(customer);
            if(rows != 1){
                // 新增错误, 回滚
                throw new RuntimeException("新增客户失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return true;
    }

    @Override
    public Map<String, Object> getCustomersByPage(int page, int rows) {
        Map<String, Object> resultMap = new HashMap<>();
        // 使用PageHelper插件,实现分页逻辑。
        PageHelper.startPage(page, rows);
        List<Customer> customerList = customerMapper.selectCustomers();
        // 当前页面显示的内容
        resultMap.put("customerList", customerList);
        // 当前页码
        resultMap.put("currentPage", page);

        // 查询总计数据行数,计算总计页码
        int totalRows = customerMapper.selectCount();
        int totalPages = totalRows % rows == 0 ? totalRows/rows : (totalRows/rows + 1);

        // 总计页码
        resultMap.put("totalPages", totalPages);
        return resultMap;
    }
}

PhoneServiceImpl

package com.alvin.service.impl;

import com.alvin.mapper.PhoneMapper;
import com.alvin.pojo.Phone;
import com.alvin.service.PhoneService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PhoneServiceImpl implements PhoneService {
    @Autowired
    private PhoneMapper phoneMapper;

    /**
     * 新增联系方式。 抛出异常,回滚事务。
     * @param phone
     * @return
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public boolean addPhone(Phone phone) {
        int rows = phoneMapper.insert(phone);
        if(rows != 1){
            // 新增失败,回滚事务
            throw new RuntimeException("新增联系方式失败");
        }
        return true;
    }
}

CustomerService接口

package com.alvin.service;

import java.util.Map;

import com.alvin.pojo.Customer;
import org.springframework.web.multipart.MultipartFile;

public interface CustomerService {
    Map<String, Object> getCustomersByPage(int page, int rows);

    boolean addCustomer(Customer customer, MultipartFile uploadImg);

    Customer getCustomerById(Integer id);

    boolean modifyCustomer(Customer customer, MultipartFile uploadImg);

    boolean removeCustomer(Integer id);
}

PhoneService接口

package com.alvin.service;

import com.alvin.pojo.Phone;

public interface PhoneService {
    boolean addPhone(Phone phone);
}

MyApplication启动类

package com.alvin;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 启动类约束。 不要写在default包下。 默认只扫描当前类所在包,及所有子孙包。
@SpringBootApplication
// basePackages属性,只为提高扫描效率。 默认扫描当前类所在包及所有子孙包。
@MapperScan(basePackages = {"com.alvin.mapper"})
public class MyApplication {
    public static void main(String[] args) {
        // 读取spring.factories文件中的启动类、配置类、初始化器,实现环境的创建。
        SpringApplication.run(MyApplication.class, args);
    }
}

Mybatis映射

CustomerMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 找dtd或xsd文件的关键字是: factory,builder,binding,xml,context
     <!ELEMENT 标签名 (#PCDATA | 子标签名)> 标签定义
       子标签数量定义:   * 0~n个    + 1~n个   ? 0~1个    , 顺序
     <!ATTLIST 标签名  属性名  属性类型或可选值  属性特征>
       属性类型或可选值 :
         CDATA 字符串
         NMTOKENS 多个字符串,用空格分隔的多个字符串
         (值1 |值2) 枚举,可选值
       属性特征:
         #IMPLIED - 可选属性
         #REQUIRED - 必要属性
         '值' - 默认值

     where 标签 -
     如果标签内没有条件SQL,不拼接 where 子句语法。
     如果标签内的第一个条件前 有 and 或 or,自动删除。
 -->
<mapper namespace="com.alvin.mapper.CustomerMapper">
    <resultMap id="customerMap" type="com.alvin.pojo.Customer">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="gender" property="gender"/>
        <result column="age" property="age"/>
        <result column="img" property="img"/>
        <result column="orig_img" property="origImg"/>
    </resultMap>
    <resultMap id="customerPhoneListMap" type="com.alvin.pojo.Customer">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="gender" property="gender"/>
        <result column="age" property="age"/>
        <result column="img" property="img"/>
        <result column="orig_img" property="origImg"/>
        <collection property="phoneList" javaType="java.util.List"
          ofType="com.alvin.pojo.Phone">
            <id column="p_id" property="id"/>
            <result column="phone_no" property="phoneNo"/>
            <result column="customer_id" property="customerId"/>
        </collection>
    </resultMap>

    <delete id="deleteCustomer">
        delete from tb_customer
        <where>
            id = #{id}
        </where>
    </delete>

    <!-- set标签的特性。 如果标签内无SQL, 不拼接set子句语法。
         标签内的最后一个字符如果是',',自动删除。
         trim - 字符串处理标签,可以为标签内部的字符串前后删除指定的字符串或增加指定的字符串
           prefixOverrides - 删除前缀
           prefix - 增加前缀
           suffixOverrides - 删除后缀
           suffix - 增加后缀
     -->
    <update id="update">
        update tb_customer
        <set>
            <trim suffixOverrides=",">
            <if test="name != null">
                name = #{name},
            </if>
            <if test="age != 0">
                age = #{age},
            </if>
            <if test="gender != null">
                gender = #{gender},
            </if>
            <if test="img != null">
                img = #{img},
            </if>
            <if test="origImg != null">
                orig_img = #{origImg},
            </if>
            </trim>
        </set>
        <where>
            id = #{id}
        </where>
    </update>

    <select id="selectById" resultMap="customerPhoneListMap">
        select
          c.id, c.name, c.gender, c.age, c.img, c.orig_img,
          p.id as p_id, p.phone_no, p.customer_id
        from
          tb_customer c
            left join
          tb_phone p
            on c.id = p.customer_id
        <where>
            and c.id = #{id}
        </where>
    </select>
    <insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into tb_customer(id, name, gender, age, img, orig_img)
        values(default, #{name}, #{gender}, #{age}, #{img}, #{origImg})
    </insert>
    <select id="selectCustomers" resultMap="customerMap">
        select id, name, gender, age, img, orig_img from tb_customer
    </select>
    <!-- _int 是简单类型int整数。  int 是包装类型Integer整数 都是MyBatis内置类型。 -->
    <select id="selectCount" resultType="_int">
        select count(id) from tb_customer
    </select>
</mapper>

PhoneMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.alvin.mapper.PhoneMapper">
    <insert id="insert" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into tb_phone(id, phone_no, customer_id)
        values(default, #{phoneNo}, #{customerId})
    </insert>
    <delete id="deleteByCustomer">
        delete from tb_phone
        <where>
            customer_id = #{id}
        </where>
    </delete>
</mapper>

前台

addCustomer.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>客户联系方式管理系统</title>
</head>
<body>
    <div style="width: 800px; margin: auto">
        <form action="/addCustomer" method="post" enctype="multipart/form-data">
            <div style="width: 500px; margin: auto; text-align: left">
                <label style="width: 200px; padding-right: 5px; text-align: right">姓名:</label>
                <input type="text" name="name">
            </div>
            <div style="width: 500px; margin: auto; text-align: left">
                <label style="width: 200px; padding-right: 5px; text-align: right">性别:</label>
                <input type="radio" name="gender" value="">&nbsp;&nbsp;&nbsp;
                <input type="radio" name="gender" value=""></div>
            <div style="width: 500px; margin: auto; text-align: left">
                <label style="width: 200px; padding-right: 5px; text-align: right">年龄:</label>
                <input type="text" name="age">
            </div>
            <div style="width: 500px; margin: auto; text-align: left">
                <label style="width: 200px; padding-right: 5px; text-align: right">头像:</label>
                <input type="file" name="uploadImg">
            </div>
            <div style="width: 600px; text-align: center; margin: auto">
                <input type="submit" value="提交"> &nbsp;&nbsp;&nbsp;&nbsp;
                <input type="reset" value="重置">
            </div>
        </form>
    </div>
</body>
</html>

addPhone.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>客户联系方式管理系统</title>
</head>
<body>
    <div style="width: 800px; margin: auto; text-align: center">
        <form action="/addPhone" method="post">
            <input type="hidden" name="customerId" th:value="${customerId}">
            <div style="width: 400px; margin: auto; text-align: center">
                <label>电话:</label>
                <input type="text" name="phoneNo">
            </div>
            <div style="width: 800px; margin: auto; text-align: center">
                <input type="submit" value="提交">
            </div>
        </form>
    </div>
</body>
</html>

error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>客户联系方式管理系统</title>
</head>
<body style="text-align: center; margin: auto">
    <h3>服务器忙,请稍后重试!<a href="/">返回首页</a></h3>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>客户联系方式管理系统</title>
</head>
<body style="text-align: center">
    <h3>客户联系方式管理系统</h3>
    <div style="width:800px; margin: auto; text-align: right; padding-right: 20px">
        <a th:href="@{/toAddCustomer}">新增客户</a>
    </div>
    <!-- 分页显示客户数据 -->
    <table style="text-align: center; margin: auto; width: 800px" border="1" cellspacing="0" cellpadding="0">
        <caption>客户列表</caption>
        <thead>
        <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>年龄</th>
            <th>头像</th>
            <th>头像文件名</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="customer: ${customerList}">
            <th th:text="${customer.id}"></th>
            <th th:text="${customer.name}"></th>
            <th th:text="${customer.gender}"></th>
            <th th:text="${customer.age}"></th>
            <th>
                <img th:src="@{${customer.img}}" style="height:40px"/>
            </th>
            <th th:text="${customer.origImg}"></th>
            <th>
                <a th:href="@{/showCustomer(id=${customer.id})}">查看</a>
                <a th:href="@{/removeCustomer(id=${customer.id})}">删除</a>
            </th>
        </tr>
        <tr>
            <th colspan="7">
                <a th:if="${currentPage != 1}" th:href="@{/index(page=${currentPage-1})}">上一页</a>
                <a th:if="${currentPage != totalPages}" th:href="@{/index(page=${currentPage+1})}">下一页</a>
            </th>
        </tr>
        </tbody>
    </table>
</body>
</html>

modifyCustomer.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div style="width:800px; margin: auto; text-align: center">
        <form action="/modifyCustomer" method="post" enctype="multipart/form-data">
            <input type="hidden" name="id" th:value="${customer.id}">
            <table cellspacing="0" cellpadding="0" border="1" style="width:100%">
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name" th:value="${customer.name}"></td>
                </tr>
                <tr>
                    <td>性别</td>
                    <td>
                        <div th:if="${customer.gender == ''}">
                            <input type="radio" value="" name="gender" checked><input type="radio" value="" name="gender"></div>
                        <div th:if="${customer.gender == ''}">
                            <input type="radio" value="" name="gender"><input type="radio" value="" name="gender" checked></div>
                    </td>
                </tr>
                <tr>
                    <td>年龄</td>
                    <td><input type="text" name="age" th:value="${customer.age}"></td>
                </tr>
                <tr>
                    <td>头像</td>
                    <td>
                        <img th:src="@{${customer.img}}" style="height: 50px">
                        <br>
                        <input type="file" name="uploadImg">
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input type="submit" value="修改">&nbsp;&nbsp;&nbsp;
                        <a th:href="@{/showCustomer(id=${customer.id})}">返回</a>
                    </td>
                </tr>
            </table>
        </form>
    </div>
</body>
</html>

showCustomer.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>客户联系方式管理系统</title>
</head>
<body>
    <div style="width: 800px; margin: auto; text-align: right">
        <a th:href="@{/toModifyCustomer(id=${customer.id})}">修改客户</a>
        &nbsp;&nbsp;&nbsp;
        <a th:href="@{/toAddPhone(customerId=${customer.id})}">新增联系方式</a>
        &nbsp;&nbsp;&nbsp;
        <a th:href="@{/}">返回首页</a>
    </div>
    <div style="width: 800px; margin: auto; text-align: center">
        <table cellpadding="0" cellspacing="0" border="1" style="width:100%">
            <caption>客户详情</caption>
            <tr>
                <td style="width:20%">客户信息</td>
                <td>
                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%">
                        <tr>
                            <td>姓名</td>
                            <td th:text="${customer.name}"></td>
                        </tr>
                        <tr>
                            <td>性别</td>
                            <td th:text="${customer.gender}"></td>
                        </tr>
                        <tr>
                            <td>年龄</td>
                            <td th:text="${customer.age}"></td>
                        </tr>
                        <tr>
                            <td>头像</td>
                            <td>
                                <img style="height: 50px" th:src="@{${customer.img}}">
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
            <tr>
                <td style="width:20%">联系方式</td>
                <td>
                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%">
                        <tr th:if="${customer.phoneList.size() > 0}" th:each="phone:${customer.phoneList}">
                            <td>电话</td>
                            <td th:text="${phone.phoneNo}"></td>
                            <td>修改和删除</td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    </div>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_41424688/article/details/107644643
今日推荐