JavaWeb开发 —— SpringBootWeb综合案例

news2024/11/18 4:34:15

通过综合案例,我们来了解和学习在开发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. 环境搭建

  • 准备数据库表(dept、emp) 。
    -- 部门管理
    create table dept(
        id int unsigned primary key auto_increment comment '主键ID',
        name varchar(10) not null unique comment '部门名称',
        create_time datetime not null comment '创建时间',
        update_time datetime not null comment '修改时间'
    ) comment '部门表';
    
    insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());
    
    
    
    -- 员工管理(带约束)
    create table emp (
      id int unsigned primary key auto_increment comment 'ID',
      username varchar(20) not null unique comment '用户名',
      password varchar(32) default '123456' comment '密码',
      name varchar(10) not null comment '姓名',
      gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
      image varchar(300) comment '图像',
      job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
      entrydate date comment '入职时间',
      dept_id int unsigned comment '部门ID',
      create_time datetime not null comment '创建时间',
      update_time datetime not null comment '修改时间'
    ) comment '员工表';
    
    INSERT INTO emp
    	(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
    	(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
    	(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
    	(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
    	(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
    	(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
    	(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
    	(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
    	(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
    	(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
    	(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
    	(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
    	(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
    	(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
    	(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
    	(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
    	(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2007-01-01',2,now(),now()),
    	(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
    
  • 创建springboot工程,引入对应的起步依赖(web、mybatis、mysql驱动、lombok)配置文件。
  • application.properties中引入mybatis的配置信息,准备对应的实体类。
  • 准备对应的Mapper、Service(接口、实现类)、Controller基础结构。

3. 开发规范

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

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

  • 传统风格:
    http://localhost : 8080/user/getById?id=1  //GET:查询ia为1的用户
    http://localhost : 8080/user/saveUser      //POST:新增用户
    http://localhost :8080/user/updateUser    //POST:修改用户
    http://localhost :8080/user/deleteUser?id=1 //GET:删除id为1的用户
    
  • REST风格:URL定位资源、HTTP动词描述操作
    http://localhost:8080/users/1    //GET:查询id为1的用户
    http://localhost:8080/users      //POST:新增用户
    http://localhost:8080/users      //PUT:修改用户
    http://localhost:8080/users/1    //DELETE:删除id为1的用户
    

注意事项:

  • REST是风格,是约定方式,约定不是规定,可以打破。
  • 描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books ...
@Data
@NoArgsConstructor
@AllArgsConstructor
public 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. 查询部门

  • 查询全部数据(由于部门数据比较少,不考虑分页)。

@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    //@RequestMapping(value = "/depts",method = RequestMethod.GET); 指定请求方式为GET
    @GetMapping("/depts")
    public Result list(){
        //调用Service查询部门数据
        List<Dept> deptList = deptService.list();

        return Result.success(deptList);
    }
}

public interface DeptService {
    /**
     *
     * 查询全部部门数据
     */
    List<Dept> list();
}

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    /**
     * 查询全部部门数据
     */
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }
}

@Mapper
public interface DeptMapper {

    /**
     * 查询全部部门数据
     */
    @Select("select * from dept;")
    List<Dept> list();
   
}

2. 前后端联调

  • 将资料中提供的 "前端工程" 文件夹中的压缩包,拷贝到一个没有中文不带空格的目录下,解压 nginv-1.22.0-tlias.zip。
  • 启动nginx,访问测试:http://localhost:90

3. 删除部门

  • 弹出确认框,提示 "您确定要删除该部门的信息吗?" 如果选择确定,则删除该部门,删除成功后,重新刷新列表页面。如果选择了取消,则不执行任何操作。

@RestController
public 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);
}

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    /**
     * 删除部门数据
     *
     */
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }
}

@Mapper
public interface DeptMapper {
    /**
     * 根据id删除部门数据
     */
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);
   
}

4. 新增部门

  • 点击新增部门,会打开新增部门的页面。
  • 部门名称,必填,唯一,长度为2-10位。

@RestController
public 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);
}

@Service
public 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);
    }
}

@Mapper
public interface DeptMapper {
    /**
     * 新增部门信息
     */
    @Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime}) ")
    void insert(Dept dept);
}

三、员工管理

1. 分页查询

  • 设置请求参数默认值:@RequestParam(defaultvalue="7")

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

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

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

/**
 * 员工管理Controller
 */
//@Slf4j  - lombok日志
@RestController
public 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);
}

@Service
public 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<Emp> empList = empMapper.page(start,pageSize);
        //封装pagebean对象
        PageBean pageBean = new PageBean(count,empList);
        return pageBean;
    }
}

@Mapper
public interface EmpMapper {
    /**
     *查询总记录数
     */
    @Select("select count(*) from emp")
    public Long count();

    /**
     *
     * 分页查询获取列表数据
     */
    @Select("select * from emp limit #{start},#{pageSize}")
    public List<Emp> page(Integer start,Integer pageSize);
}

2. PageHelper分页插件

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

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

  • 引入依赖:
    <!--        pagehelper依赖-->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.4.2</version>
            </dependency>
  • 分页代码:
    @Service
    public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;
        @Override
        public PageBean page(Integer page, Integer pageSize){
            //设置分页参数
        PageHelper.startPage(page,pageSize);
            //执行查询
            List<Emp> empList = empMapper.list();
            Page<Emp> p = (Page<Emp>) empList;
            //封装pagebean对象
            PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
            return pageBean;
        }
    }
    
    @Mapper
    public interface EmpMapper {
    /**
         * 员工信息查询
         */
        @Select("select * from emp")
        public List<Emp> list();
    }

3. 条件分页查询

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

@RestController
public 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);
}

@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
    @Override
    public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end){
        //设置分页参数
    PageHelper.startPage(page,pageSize);
        //执行查询
        List<Emp> empList = empMapper.list(name, gender, begin, end);
        Page<Emp> p = (Page<Emp>) empList;
        //封装pagebean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }
}

@Mapper
public interface EmpMapper {
    public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}

 <!--    EmpMapper.xml-->
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--    条件查询-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select *
        from emp
        <where>
            <if test="name != null">
                name like concat('%', #{name}, '%')
            </if>
            <if test="gender != null">
                and gender = #{gender}
            </if>
            <if test="begin != null and end != null">
                and entrydate between #{begin} and #{end}
            </if>
        </where>
        order by update_time desc
    </select>
</mapper>

4. 删除员工

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

  • 如果我们仅仅开发一个批量删除的接口是可行的,因为删除一条元素也是特殊的批量删除。

@RestController
public class EmpController {
    @Autowired
    private EmpService empService;

    /**
     * 删除员工
     */
    @DeleteMapping("/emps/{ids}")
    public Result delete(@PathVariable List<Integer> ids){
        //log.info("删除员工:{},",ids);
        empService.delete(ids);
        return Result.success();
    }
}

public interface EmpService {
    void delete(List<Integer> ids);
}

@Service
public class EmpServiceImpl implements EmpService {
@Override
    public void delete(List<Integer> ids) {
        empMapper.delete(ids);
    }
}

@Mapper
public interface EmpMapper {
    void delete(List<Integer> ids);
}

 <!--    EmpMapper.xml-->
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--    批量删除操作-->
    <delete id="delete">
        delete
        from emp
        where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
</mapper>

四、员工信息

1. 新增员工

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

@RestController
public 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);
}

@Service
public class EmpServiceImpl implements EmpService {
@Override
    public void save(Emp emp) {
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.insert(emp);
    }
}

@Mapper
public interface EmpMapper {
    void delete(List<Integer> ids);
}

@Mapper
public 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  简介

  • 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
  • 文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

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

  • 表单项 type= " file "
  • 表单提交方式 post
  • 表单的enctype属性 multipart/form-data
<form action="/upload" method="post" enctype="multipart/form-data">
  姓名: <input type="text” name="username"<br>
  年龄: <input type="text"name="age"><br>
  头像: <input type="file" name="image"><br>
  <input type="submit" value="提交">
</form>

② 服务端接收文件:MultipartFile

//@slf4j
@RestController
public 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() ;获取接收到的文件内容的输入流。
@RestController
public 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

① 介绍:

  • 阿里云是阿里巴巴集团旗下全球领先的云计算公司,也是国内最大的云服务提供商。
  • 阿里云对象存储OSS (Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
  • 官网:https://www.aliyun.com/
  • 使用步骤:

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

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

  • 添加依赖:
    <!--        阿里云oss依赖-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.15.1</version>
            </dependency>
            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>2.3.1</version>
            </dependency>
            <dependency>
                <groupId>javax.activation</groupId>
                <artifactId>activation</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- no more than 2.3.3-->
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>2.3.3</version>
            </dependency>
  • 简单上传文件流代码:
    import com.aliyun.oss.ClientException;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.OSSException;
    import com.aliyun.oss.model.PutObjectRequest;
    import com.aliyun.oss.model.PutObjectResult;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
            String accessKeyId = "yourAccessKeyId";
            String accessKeySecret = "yourAccessKeySecret";
            // 填写Bucket名称,例如examplebucket。
            String bucketName = "examplebucket";
            // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
            String objectName = "exampledir/exampleobject.txt";
            // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
            // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
            String filePath= "D:\\localpath\\examplefile.txt";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    
            try {
                InputStream inputStream = new FileInputStream(filePath);
                // 创建PutObjectRequest对象。
                PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
                // 设置该属性可以返回response。如果不设置,则返回的response为空。
                putObjectRequest.setProcess("true");
                // 创建PutObject请求。
                PutObjectResult result = ossClient.putObject(putObjectRequest);
                // 如果上传成功,则返回200。
                System.out.println(result.getResponse().getStatusCode());
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    } 

③ 项目集成:

  • 引入阿里云OSS上传文件工具类(由官方的示例代码改造而来)
    package com.itheima.utils;
    
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    import java.io.*;
    import java.util.UUID;
    
    /**
     * 阿里云 OSS 工具类
     */
    @Component
    public class AliOSSUtils {
        private String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        private String accessKeyId = "LTAI5tMXhdNWon5c2k4fbSd4";
        private String accessKeySecret = "3fleUo57n8X42mijz6WsCUKznmumw8";
        private String bucketName = "web-tlias";
    
        /**
         * 实现上传图片到OSS
         */
        public String upload(MultipartFile file) throws IOException {
            // 获取上传的文件的输入流
            InputStream inputStream = file.getInputStream();
    
            // 避免文件覆盖
            String originalFilename = file.getOriginalFilename();
            String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
    
            //上传文件到 OSS
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            ossClient.putObject(bucketName, fileName, inputStream);
    
            //文件访问路径
            String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
            // 关闭ossClient
            ossClient.shutdown();
            return url;// 把上传到oss的路径返回
        }
    
    }
    
  • 上传图片接口开发
    //@slf4j
    @RestController
    public class UploadController {
        @Autowired
        private AliOSSUtils aliOSSUtils;
    
        //阿里云oss上传文件
        @PostMapping("/upload")
        public Result upload(MultipartFile image) throws IOException {
            //log.info("文件上传文件名:{}",image.getOriginalFilename());
            //调用阿里云oss文件上传工具类
           String url =  aliOSSUtils.upload(image);
           //log.info("文件上传成功,上传文件url为:{}",url);
            return Result.success(url);
        }
    }

3. 修改员工

3.1  查询回显

@RestController
public class EmpController {
    @Autowired
    private EmpService empService;
    /**
     * 根据id查员工
     */
    @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);
}

@Service
public class EmpServiceImpl implements EmpService {
@Override
    public Emp getById(Integer id) {
        return empMapper.getById(id);
    }
}

@Mapper
public interface EmpMapper {
    void delete(List<Integer> ids);
}

@Mapper
public interface EmpMapper {
 @Select("select * from emp where id = #{id}")
    Emp getById(Integer id);
}

3.2  修改员工信息

@RestController
public 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);
}

@Service
public class EmpServiceImpl implements EmpService {
@Override
    public void update(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.update(emp);
    }
}

@Mapper
public interface EmpMapper {
    void delete(List<Integer> ids);
}

 <!--    EmpMapper.xml-->
<mapper namespace="com.itheima.mapper.EmpMapper">
     <update id="update">
        update emp
        <set>
            <if test=" username!= null">username = #{username},</if>
            <if test=" password!= null">password = #{password},</if>
            <if test=" name!= null">name = #{name},</if>
            <if test=" gender!= null">gender = #{gender},</if>
            <if test=" image!= null">image = #{image},</if>
            <if test=" job!= null">job = #{job},</if>
            <if test=" entrydate!= null">entrydate = #{entrydate},</if>
            <if test=" deptId!= null">dept_id = #{deptId},</if>
            <if test=" updateTime!= null">update_time = #{updateTime}</if>
        </set>
        where id = #{id}
    </update>
</mapper>

五、配置文件

1. 参数配置化

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

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

#阿里云oss配置文件
aliyun.oss.endpoint=https://oss-cn-hangzhou.aliyuncs.com
aliyun.oss.accessKeyId=LTAI5tMXhdNWon5c2k4fbSd4
aliyun.oss.accessKeySecret=3fleUo57n8X42mijz6WsCUKznmumw8
aliyun.oss.bucketName=web-tlias
@Component
public 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 (推荐)

简洁、数据为中心

 ① 基本语法:

  • 大小写敏感。
  • 数值前边必须有空格,作为分隔符。
  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格。(idea中会自动将Tab转换为空格)
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
  • #表示注释,从这个字符一直到行尾, 都会被解析器忽略。

② yml数据格式:

  • 对象 / Map集合:
    user:
      name: zhangsan
      age: 18
      password: 123456
  • 数组 / List / Set集合:
    hobby:
      - java
      - game
      - sport

 ③ 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 + '\'' +
                '}';
    }
}
@Component
public class AliOSSUtils {
    @Autowired
    private AliOSSProperties aliOSSProperties;

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws IOException {
        //获取阿里云oss参数
        String endpoint = aliOSSProperties.getEndpoint();
        String accessKeyId = aliOSSProperties.getAccessKeyId();
        String accessKeySecret = aliOSSProperties.getAccessKeySecret();
        String bucketName = aliOSSProperties.getBucketName();
}

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

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

② @ConfigurationProperties与@Value 对比:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/451736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Postgis导出shp和gdb数据库(Postgre入门九)

背景 有时候我们需要将postgis数据库中的空间数据表导出shp格式,而PG自带的PostGIS Shapefile Import/Export Manager 导出shp大部分时候是可以用的,但是它有个缺点是,当shp字段名称超过10个字节时,字段会被切掉,如字段“afdskskkfkfjdj”被切掉后是“afdskskkfk”,所以…

文案自动修改软件-文案自动改写的免费软件下载

文章生成器ai写作机器人 随着人工智能技术的飞速发展&#xff0c;越来越多的新型产品被推向市场。其中&#xff0c;文章生成器AI写作机器人是一个备受关注的新兴行业。它使用机器学习和自然语言处理等技术&#xff0c;为用户自动生成高质量的文章和内容&#xff0c;帮助用户在…

基于OpenCV与深度神经网络——实现证件识别扫描并1比1还原证件到A4纸上

前言 1.用拍照的证件照片正反面&#xff0c;实现用证件去复印到A4纸上的效果&#xff0c;还有证件的格式化识别。 图1&#xff1a;把拍照的证件1比1还原证件到A4纸上 图2&#xff1a;证件OCR格式化识别 2.使用Yolo做目标识别,Enet做边缘检测&#xff0c;Paddle OCR做文字识别&…

【数据结构与算法】常用数据结构(一)

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4aa;&#x1f4…

燃气管道定位83KHZ地下电子标识器探测仪ED-8000操作说明1

1、功能简要说明 ED-8000地下电子标识器探测仪是华翔天诚推出的一款可支持模拟电子标识器&#xff08;无 ID&#xff09;探测和数字 ID 电子标识器 探测两种工作模式&#xff0c;在模拟电子标识器&#xff08;无 ID&#xff09;探测模式下&#xff0c;可探测 所有按标准频率生…

Unity-ML-Agents安装

目录 1.下载ML-Agents 1.1 前往官网 1.2 选择版本 1.3 下载文件 2.下载Anaconda 3.虚拟环境 3.1 构建虚拟环境 3.2 创建项目&#xff0c;导入package.json 3.2.1 创建项目&#xff0c;导入package.json 3.2.2 导入成功 3.2.3 将模板项目拖入unity项目中 3.3 开始训练 …

低代码感觉很能打——可视化搭建系统,把格局做大

有人说「可视化搭建系统」说到底只是重复造轮子产生的玩具&#xff1b; 有人说「可视化搭建系统」本质是组件枚举&#xff0c;毫无意义。 片面的认知必有其产生的道理&#xff0c;但我们不妨从更高的角度出发&#xff0c;并真切落地实践&#xff0c;也许你会发现&#xff1a;我…

Java面试题总结 | Java面试题总结5- 数据结构模块(持续更新)

数据结构 文章目录 数据结构顺序表和链表的区别HashMap 和 Hashtable 的区别Java中用过哪些集合&#xff0c;说说底层实现&#xff0c;使用过哪些安全的集合类Java中线程安全的基本数据结构有哪些ArrayList、Vector和LinkedList有什么共同点与区别&#xff1f;ArrayList和Linke…

怎样正确做web应用的压力测试?

web应用&#xff0c;通俗来讲就是一个网站&#xff0c;主要依托于浏览器实现其功能。 提到压力测试&#xff0c;我们想到的是服务端压力测试&#xff0c;其实这是片面的&#xff0c;完整的压力测试包含服务端压力测试和前端压力测试。 下文将从以下几部分内容展开&#xff1a…

源码简读 - AlphaFold2的2.3.2版本源码解析 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/130323566 时间&#xff1a;2023.4.22 官网&#xff1a;https://github.com/deepmind/alphafold AlphaFold2是一种基于深度学习的方法…

torch中fft和ifft新旧版本使用

pytorch旧版本&#xff08;1.7之前&#xff09;中有一个函数torch.rfft()&#xff0c;但是新版本&#xff08;1.8、1.9&#xff09;中被移除了&#xff0c;添加了torch.fft.rfft()&#xff0c;但它并不是旧版的替代品。 torch.fft label_fft1 torch.rfft(label_img4, signal…

25岁走出外包后,感到迷茫了.....

我认识一个老哥&#xff0c;他前段时间从外包出来了&#xff0c;他在外包干了3年左右的点工&#xff0c;可能也是自身的原因&#xff0c;也没有想到提升自己的技术水平&#xff0c;后面觉得快废了&#xff0c;待着没意思就出来了&#xff0c;出来后他自己更迷茫了&#xff0c;本…

Linux安装Jenkins搭配Gitee自动化部署Springboot项目

目录 前言一、环境准备二、全局工具配置jdk、maven、git三、配置Gitee四、新建任务-部署Springboot项目 前言 Jenkins是一款流行的开源持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;工具。它可以帮助开发人员自动构建、测试和部署软件应用程序&…

广州蓝景分享—快速了解Typescript 5.0 中重要的新功能

作为一种在开发人员中越来越受欢迎的编程语言&#xff0c;TypeScript 不断发展&#xff0c;带来了大量的改进和新功能。在本文中&#xff0c;我们将深入研究 TypeScript 的最新迭代版本 5.0&#xff0c;并探索其最值得注意的更新。 1.装饰器 TypeScript 5.0 引入了改进的装饰…

二、SQLServer 的适配记录

SQLServer 适配记录 说明:由于 SQLSERVER 数据库本身和MYSQL数据库有一定的语法,创表结构,物理模式等差别,在适配过程中,可能会出现各种错误情况,可参考本次适配记录。 当前环境: 适配项目:JDK11,SpringBoot服务。 适配数据库:SELECT @@VERSION,得 Microsoft SQL …

ProtocolBuffer入门和使用

<<<<<<< HEAD 基础 入门 优势 protocol buffer主要用于结构化数据串行化的灵活、高效、自动的方法&#xff08;简单来说就是结构化数据的可串行化传输&#xff0c;类似JSON、XML等&#xff09;。 比XML解析更快&#xff1a;解析的层数更少&#xff0c;…

【技术发烧】MySqlServer,MySQL WorkBench安装详细教程

目录 一.下载安装MySQLSever 1.下载 2.安装 1.解压 2.编写配置文件 二.初始化数据库 1.以管理员身份打开命令提示符 2.初始化数据库 3.安装mysql服务并启动 4.连接MySQL 5. 修改密码 三.MySQL WorkBench下载 一.下载安装MySQLSever 1.下载 下载路径&#xff1a;https:/…

java导入导出excel数据图片合成工具

目录 java导出和导入excel数据java读取excel数据java数据导出成excel表格 java服务端图片合成的工具 java导出和导入excel数据 可以使用hutool的ExcelUtil工具。 在项目中加入以下依赖&#xff1a; <dependency><groupId>cn.hutool</groupId><artifactI…

【计算机基础】绝对路径和相对路径

目录 一.绝对路径 二.相对路径 例如 三.举例 一.绝对路径 绝对路径是指从根目录开始的完整路径&#xff0c;包括所有父目录的路径&#xff0c;直到目标文件或者目录 所在的位置。 全文件名全路径文件名绝对路经完整的路径 例如&#xff0c;在windows系统中&#xff0c;绝…

《Linux基础》09. Shell 编程

Shell 编程 1&#xff1a;Shell 简介2&#xff1a;Shell 脚本2.1&#xff1a;规则与语法2.2&#xff1a;执行方式2.3&#xff1a;第一个 Shell 脚本 3&#xff1a;变量3.1&#xff1a;系统变量3.2&#xff1a;用户自定义变量3.2.1&#xff1a;规则3.2.2&#xff1a;基本语法3.2…