文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaWeb开发 —— SpringBootWeb综合案例

2023-09-26 06:26

关注

通过综合案例,我们来了解和学习在开发Web程序时,前端程序和后端程序以及数据库三者之间是如何交互、如何协作的,而通过综合案例也来掌握通过接口文档开发服务端接口的能力。

目录

一、准备工作

1. 需求说明

2. 环境搭建

3. 开发规范

二、部门管理

1. 查询部门

2. 前后端联调

3. 删除部门

4. 新增部门

三、员工管理

1. 分页查询

2. PageHelper分页插件

3. 条件分页查询

4. 删除员工

四、员工信息

1. 新增员工

2. 文件上传

2.1  简介

2.2  本地存储

2.3  阿里云OSS

3. 修改员工

3.1  查询回显

3.2  修改员工信息

五、配置文件

1. 参数配置化

2. yml配置文件

3. @ConfigurationProperties注解 


一、准备工作

1. 需求说明

部门管理:

  • 杏询部门列表
  • 删除部门
  • 新增部门
  • 修改部门

员工管理:

  • 查询员工列表(分页、条件)
  • 删除员工
  • 新增员工
  • 修改员工

2. 环境搭建

3. 开发规范

案例基于当前最为主流的前后端分离模式进行开发。在开发每一功能接口时仔细阅读接口文档并严格遵守接口文档进行开发,才能保证我们开发的功能可以顺利与前端对接。而在本案例中,前后端交互使用的是 Restful 风格接口

REST (REpresentational State Transfer),表述性状态转换,它是一种软件架构风格

注意事项:

  • REST是风格,是约定方式,约定不是规定,可以打破。
  • 描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books ...
@Data@NoArgsConstructor@AllArgsConstructorpublic class Result {    private Integer code;//响应码,1 代表成功; 0 代表失败    private String msg;  //响应信息 描述字符串    private Object data; //返回的数据    //增删改 成功响应    public static Result success(){        return new Result(1,"success",null);    }    //查询 成功响应    public static Result success(Object data){        return new Result(1,"success",data);    }    //失败响应    public static Result error(String msg){        return new Result(0,msg,null);    }}

二、部门管理

1. 查询部门

@RestControllerpublic class DeptController {    @Autowired    private DeptService deptService;    //@RequestMapping(value = "/depts",method = RequestMethod.GET); 指定请求方式为GET    @GetMapping("/depts")    public Result list(){        //调用Service查询部门数据        List deptList = deptService.list();        return Result.success(deptList);    }}public interface DeptService {        List list();}@Servicepublic class DeptServiceImpl implements DeptService {    @Autowired    private DeptMapper deptMapper;        @Override    public List list() {        return deptMapper.list();    }}@Mapperpublic interface DeptMapper {        @Select("select * from dept;")    List list();   }

2. 前后端联调

3. 删除部门

@RestControllerpublic class DeptController {    @Autowired    private DeptService deptService;         @DeleteMapping("/depts/{id}")    public Result delete(@PathVariable Integer id){        //log.info("根据id删除部门:{}",id);        //调用Service删除部门数据        deptService.delete(id);        return Result.success();    }}public interface DeptService {        void delete(Integer id);}@Servicepublic class DeptServiceImpl implements DeptService {    @Autowired    private DeptMapper deptMapper;        @Override    public void delete(Integer id) {        deptMapper.deleteById(id);    }}@Mapperpublic interface DeptMapper {        @Delete("delete from dept where id = #{id}")    void deleteById(Integer id);   }

4. 新增部门

@RestControllerpublic class DeptController {    @Autowired    private DeptService deptService;         @PostMapping("/depts")    public Result add(@RequestBody Dept dept){        //log.info("新增部门:{}",dept);        //调用Service新增部门数据        deptService.add(dept);        return Result.success();    }}public interface DeptService {        void add(Dept dept);}@Servicepublic class DeptServiceImpl implements DeptService {    @Autowired    private DeptMapper deptMapper;        @Override    public void add(Dept dept) {        dept.setCreateTime(LocalDateTime.now());        dept.setUpdateTime(LocalDateTime.now());        deptMapper.insert(dept);    }}@Mapperpublic interface DeptMapper {        @Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime}) ")    void insert(Dept dept);}

三、员工管理

1. 分页查询

 在之前的MySQL学习中,我们知道使用 limit 关键字 实现分页查询。

服务端给客户端响应数据最终是我们所设置的Controller方法的返回值,而一个方法只能有一个返回值,而员工列表和记录数类型不一样,所以我们需要将这两项数据封装成一个实现类。

@Datepublic class PageBean{       private Long tocal;   //总记录数       private List rows;    //当前页数据列表}

//@Slf4j  - lombok日志@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;    @GetMapping("/emps")    public Result page(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){        //log.info("分页查询:参数:{},{}",page,pageSize);        //调用Service分页查询       PageBean pageBean = empService.page(page,pageSize);       return Result.success(pageBean);    }}public interface EmpService {        PageBean page(Integer page , Integer pageSize);}@Servicepublic class EmpServiceImpl implements EmpService {    @Autowired    private EmpMapper empMapper;    @Override    public PageBean page(Integer page, Integer pageSize) {        //获取总记录数        Long count = empMapper.count();        //获取分页查询结果列表        Integer start = (page - 1) * pageSize;        List empList = empMapper.page(start,pageSize);        //封装pagebean对象        PageBean pageBean = new PageBean(count,empList);        return pageBean;    }}@Mapperpublic interface EmpMapper {        @Select("select count(*) from emp")    public Long count();        @Select("select * from emp limit #{start},#{pageSize}")    public List page(Integer start,Integer pageSize);}

2. PageHelper分页插件

在上述分页查询操作中,我们定义两条Sql语句获取指定页码数据列表和总记录数,这是原始的分页查询方式,可以看到步骤固定,代码繁琐。

所以第三方组织就提供了专门实现分页查询操作功能的插件,而目前MyBatis框架中最流行的就是PageHelper分页插件 

3. 条件分页查询

 在上述分页查询代码基础上添加条件即可。

@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;    @GetMapping("/emps")    public Result page(            @RequestParam(defaultValue = "1") Integer page,            @RequestParam(defaultValue = "10") Integer pageSize,            String name, Short gender,            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){        //log.info("分页查询:参数:{},{},{},{},{},{}",page,pageSize,name,gender,begin,end);        //调用Service分页查询       PageBean pageBean = empService.page(page,pageSize,name,gender,begin,end);       return Result.success(pageBean);    }}public interface EmpService {        PageBean page(Integer page , Integer pageSize,String name, Short gender,LocalDate begin, LocalDate end);}@Servicepublic class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;    @Override    public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end){        //设置分页参数    PageHelper.startPage(page,pageSize);        //执行查询        List empList = empMapper.list(name, gender, begin, end);        Page p = (Page) empList;        //封装pagebean对象        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());        return pageBean;    }}@Mapperpublic interface EmpMapper {    public List list(String name, Short gender, LocalDate begin, LocalDate end);}                 select *        from emp                                    name like concat('%', #{name}, '%')                                        and gender = #{gender}                                        and entrydate between #{begin} and #{end}                            order by update_time desc    

4. 删除员工

 思考问题:是否要开发删除和批量删除两个接口?

@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;        @DeleteMapping("/emps/{ids}")    public Result delete(@PathVariable List ids){        //log.info("删除员工:{},",ids);        empService.delete(ids);        return Result.success();    }}public interface EmpService {    void delete(List ids);}@Servicepublic class EmpServiceImpl implements EmpService {@Override    public void delete(List ids) {        empMapper.delete(ids);    }}@Mapperpublic interface EmpMapper {    void delete(List ids);}                 delete        from emp        where id in                    #{id}            

四、员工信息

1. 新增员工

 该小节我们针对于员工基本信息的录入,图像的上传第二小节再进行仔细介绍。

@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;        @PostMapping("/emps")    public Result save(@RequestBody Emp emp){         //log.info("新增员工:{},",emp);        empService.save(emp);        return Result.success();    }}public interface EmpService {     void save(Emp emp);}@Servicepublic class EmpServiceImpl implements EmpService {@Override    public void save(Emp emp) {        emp.setCreateTime(LocalDateTime.now());        emp.setUpdateTime(LocalDateTime.now());        empMapper.insert(emp);    }}@Mapperpublic interface EmpMapper {    void delete(List ids);}@Mapperpublic interface EmpMapper {@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +            "values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")    void insert(Emp emp);}

2. 文件上传

2.1  简介

① 前端在进行文件上传时,需注意三要素:

姓名: 年龄:
头像:

② 服务端接收文件:MultipartFile

//@slf4j@RestControllerpublic class UploadController {    @PostMapping("/upload")    public Result upload(String username, Integer age, MultipartFile image){        //log.info("文件上传:{},{},{}",username,age,image);        return Result.success();    }}

2.2  本地存储

在服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘中。

MultipartFile 常用方法:

方法说明
String getOriginalFilename() ;获取原始文件名。
void transferTo(File dest) ;将接收的文件转存到磁盘文件中。
long getSize() ;获取文件的大小,单位:字节。
byte[] getBytes() ;获取文件内容的字节数组。
lnputStream getInputStream() ;获取接收到的文件内容的输入流。
@RestControllerpublic class UploadController {    @PostMapping("/upload")    public Result upload(String username, Integer age, MultipartFile image) throws IOException {        //log.info("文件上传:{},{},{}",username,age,image);        //获取原始文件名 - 1.jpg        String  originalFilename= image.getOriginalFilename();        //构造唯一文件名(不重复)-- uuid(通用唯一识别码)       int index =  originalFilename.lastIndexOf(".");       String extname  = originalFilename.substring(index);       String newFileName = UUID.randomUUID().toString() + extname;       //log.info("新的文件名:{}" , newFileName);        //将文件存储在服务器的磁盘目录中 F:\downloadfile\upload        image.transferTo(new File("F:\\downloadfile\\upload\\"+newFileName));        return Result.success();    }}

在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M。如果需要上传大文件,可以进行如下配置:

#配置单个文件最大上传大小spring.servlet.multipart.max-file-size=10MB#配置单个请求最大上传大小(一次请求可以上传多个文件)spring.servlet.multipart.max-request-size=100MB

注意问题:本地存储指将我们上传的文件全部存储在本地磁盘目录当中,但是这种方式在我们实际开发中很少使用,原因如下:

  • 全部存储在磁盘目录下,前端页面无法直接访问。
  • 项目中上传大量文件到本地磁盘目录下,而磁盘容量有限且不方便扩容又或者磁盘发生错误,损失较大。

2.3  阿里云OSS

① 介绍:

Bucket:存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。
SDK:Software Development Kit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。

② 安装:参照官方SDK编写入门程序:阿里云对象存储OSS简介

③ 项目集成:

3. 修改员工

3.1  查询回显

@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;        @GetMapping("/emps/{id}")    public Result getById(@PathVariable Integer id){        //log.info("根据id查询员工信息:{}",id);        Emp emp = empService.getById(id);        return Result.success(emp);    }}public interface EmpService {    Emp getById(Integer id);}@Servicepublic class EmpServiceImpl implements EmpService {@Override    public Emp getById(Integer id) {        return empMapper.getById(id);    }}@Mapperpublic interface EmpMapper {    void delete(List ids);}@Mapperpublic interface EmpMapper { @Select("select * from emp where id = #{id}")    Emp getById(Integer id);}

3.2  修改员工信息

@RestControllerpublic class EmpController {    @Autowired    private EmpService empService;    @PostMapping("/emps")    public Result update(@RequestBody Emp emp){        //log.info("更新员工信息:{}",emp);        empService.update(emp);        return Result.success();    }}public interface EmpService {    void update(Emp emp);}@Servicepublic class EmpServiceImpl implements EmpService {@Override    public void update(Emp emp) {        emp.setUpdateTime(LocalDateTime.now());        empMapper.update(emp);    }}@Mapperpublic interface EmpMapper {    void delete(List ids);}              update emp                    username = #{username},            password = #{password},            name = #{name},            gender = #{gender},            image = #{image},            job = #{job},            entrydate = #{entrydate},            dept_id = #{deptId},            update_time = #{updateTime}                where id = #{id}    

五、配置文件

1. 参数配置化

问题分析:上章节中我们采用了阿里云OSS工具类上传文件,在文件上传中我们定义了许多参数,比如阿里云域名、密钥以及存储空间名等。而在之前的开发中我们采用的是硬编码,就会产生问题:不方便维护和管理。

解决方案:我们可以把阿里云OSS工具类参数定义在properties配置文件当中。

#阿里云oss配置文件aliyun.oss.endpoint=https://oss-cn-hangzhou.aliyuncs.comaliyun.oss.accessKeyId=LTAI5tMXhdNWon5c2k4fbSd4aliyun.oss.accessKeySecret=3fleUo57n8X42mijz6WsCUKznmumw8aliyun.oss.bucketName=web-tlias
@Componentpublic class AliOSSUtils {    @Value("${aliyun.oss.endpoint}")    private String endpoint;    @Value("${aliyun.oss.accessKeyId}")    private String accessKeyId;    @Value("${aliyun.oss.accessKeySecret}")    private String accessKeySecret;    @Value("${aliyun.oss.bucketName}")    private String bucketName;}

2. yml配置文件

在SpringBoot项目当中支持多种配置方式文件,在之前的学习过程当中,我们一直使用的都是application.properties配置文件,配置文件名是固定的。其实还要其他类型的配置文件:

类别内容对比
xml臃肿
properties层次结构不清晰

yml / yaml (推荐)

简洁、数据为中心

 ① 基本语法:

② yml数据格式:

 ③ yml配置:在application.yml中配置上述案例相关的配置项。

spring:  # 数据库连接信息  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/tlias    username: root    password: 123456  # 文件上传配置  servlet:    multipart:      max-file-size: 10MB      max-request-size: 100MB# Mybatis配置mybatis:  configuration:    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl    map-underscore-to-camel-case: true# 阿里云oss配置aliyun:  oss:    endpoint: https://oss-cn-hangzhou.aliyuncs.com    accessKeyId: LTAI5tMXhdNWon5c2k4fbSd4    accessKeySecret: 3fleUo57n8X42mijz6WsCUKznmumw8    bucketName: web-tlias

3. @ConfigurationProperties注解 

① 问题分析:

在前面的学习时,我们将阿里云oss中四个参数属性交给properties或者yaml配置文件集中的配置管理,而在工具类中我们要想用到这四个参数就需要在成员变量前加上 @Value注解来注入外部配置文件中的属性值,并且在 @Value注解中使用 ${ } 来指定我们注入的指定值。

 但是在实际开发中,如果参数较多,在每一个成员变量前都加上 @Value注解就会繁琐。所以我们又引入了 @ConfigurationProperties注解

@Component@ConfigurationProperties(prefix = "aliyun.oss")public class AliOSSProperties {    private String endpoint;    private String accessKeyId;    private String accessKeySecret;    private String bucketName;    public AliOSSProperties() {    }    public AliOSSProperties(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {        this.endpoint = endpoint;        this.accessKeyId = accessKeyId;        this.accessKeySecret = accessKeySecret;        this.bucketName = bucketName;    }    public String getEndpoint() {        return endpoint;    }    public void setEndpoint(String endpoint) {        this.endpoint = endpoint;    }    public String getAccessKeyId() {        return accessKeyId;    }    public void setAccessKeyId(String accessKeyId) {        this.accessKeyId = accessKeyId;    }    public String getAccessKeySecret() {        return accessKeySecret;    }    public void setAccessKeySecret(String accessKeySecret) {        this.accessKeySecret = accessKeySecret;    }    public String getBucketName() {        return bucketName;    }    public void setBucketName(String bucketName) {        this.bucketName = bucketName;    }    @Override    public String toString() {        return "AliOSSProperties{" +                "endpoint='" + endpoint + '\'' +                ", accessKeyId='" + accessKeyId + '\'' +                ", accessKeySecret='" + accessKeySecret + '\'' +                ", bucketName='" + bucketName + '\'' +                '}';    }}
@Componentpublic class AliOSSUtils {    @Autowired    private AliOSSProperties aliOSSProperties;        public String upload(MultipartFile file) throws IOException {        //获取阿里云oss参数        String endpoint = aliOSSProperties.getEndpoint();        String accessKeyId = aliOSSProperties.getAccessKeyId();        String accessKeySecret = aliOSSProperties.getAccessKeySecret();        String bucketName = aliOSSProperties.getBucketName();}

注意:当我们完成上述操作时,会发现弹出下面提示框,我们可以添加依赖解决问题。但是这个是可选操作,并不影响我们代码的运行。

            org.springframework.boot            spring-boot-configuration-processor

② @ConfigurationProperties与@Value 对比:

相同点
  • 都是用来注入外部配置的属性的。
不同点
  • @Value注解只能一一个一个的进行外部属性的注入。
  • @ConfigurationProperties'可以批量的将外部的属性配置注入到bean对象的属性中。

来源地址:https://blog.csdn.net/hdakj22/article/details/130259507

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯