Day47(17)-F:\硕士阶段\Java\课程代码\后端\web-ai-code\web-ai-project02
文件上传
服务器搭建
云服务
LTAI5t5hEbLq6RPAc5ihjWEH
vY9VD0hh9q7TcFU2H9AP9x8FPEA8hr
配置环境变量
set OSS_ACCESS_KEY_ID=LTAI5t5hEbLq6RPAc5ihjWEH
set OSS_ACCESS_KEY_SECRET=vY9VD0hh9q7TcFU2H9AP9x8FPEA8hr
设置使其生效
setx OSS_ACCESS_KEY_ID "%OSS_ACCESS_KEY_ID%"
setx OSS_ACCESS_KEY_SECRET "%OSS_ACCESS_KEY_SECRET%"
验证是否生效
echo %OSS_ACCESS_KEY_ID%
echo %OSS_ACCESS_KEY_SECRET%
阿里云搭建相关视频在107集
package com.itheima.utils;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Component
public class AliyunOSSOperator {
private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private String bucketName = "java-ai-01-david";
private String region = "cn-beijing";
public String upload(byte[] content, String originalFilename) throws Exception {
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Object完整路径,例如202406/1.png。Object完整路径中不能包含Bucket名称。
//获取当前系统日期的字符串,格式为 yyyy/MM
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
//生成一个新的不重复的文件名
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = dir + "/" + newFileName;
// 创建OSSClient实例。官方代码
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
} finally {
ossClient.shutdown();
}
return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
}
}
package com.itheima.controller;
import com.itheima.pojo.Result;
import com.itheima.utils.AliyunOSSOperator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Slf4j
@RestController
public class UploadController {
// /**
// * 本地磁盘存储,不推荐
// * @param name
// * @param age
// * @param file
// * @return
// * @throws IOException
// */
// @PostMapping("/upload")
// public Result upload(String name, Integer age, MultipartFile file) throws IOException {
// log.info("接收的参数:{},{},{}",name,age,file);
// //获取原始文件名
// String originalFilename = file.getOriginalFilename();
// //新的文件名
// String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
// String newFileName = UUID.randomUUID().toString() + extension;
// //保存文件
// //file.transferTo(new File("F:/images/"+originalFilename));
// file.transferTo(new File("F:/images/"+newFileName));
// return Result.success();
// }
@Autowired
private AliyunOSSOperator aliyunOSSOperator;
@PostMapping("/upload")
public Result upload(MultipartFile file) throws Exception {
log.info("文件上传:{}",file.getOriginalFilename());
//将文件交给OSS存储管理
String url = aliyunOSSOperator.upload(file.getBytes(), file.getOriginalFilename());
log.info("文件上传到OSS,url:"+url);
return Result.success(url);
}
}
#阿里云OSS
aliyun:
oss:
endpoint: https://oss-cn-beijing.aliyuncs.com
bucketName: java-ai-01-david
region: cn-beijing
package com.itheima.utils;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Component
public class AliyunOSSOperator {
// private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// private String bucketName = "java-ai-01-david";
// private String region = "cn-beijing";
@Value("${aliyun.oss.endpoint}")
private String endpoint ;
@Value("${aliyun.oss.bucketName}")
private String bucketName ;
@Value("${aliyun.oss.region}")
private String region ;
public String upload(byte[] content, String originalFilename) throws Exception {
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Object完整路径,例如202406/1.png。Object完整路径中不能包含Bucket名称。
//获取当前系统日期的字符串,格式为 yyyy/MM
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
//生成一个新的不重复的文件名
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = dir + "/" + newFileName;
// 创建OSSClient实例。官方代码
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
} finally {
ossClient.shutdown();
}
return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
}
}
package com.itheima.utils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliyunOSSProperties {
private String endpoint;
private String bucketName;
private String region;
}
package com.itheima.utils;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Component
public class AliyunOSSOperator {
// private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// private String bucketName = "java-ai-01-david";
// private String region = "cn-beijing";
//方式一:提供@Value注解将属性逐一注入
// @Value("${aliyun.oss.endpoint}")
// private String endpoint ;
// @Value("${aliyun.oss.bucketName}")
// private String bucketName ;
// @Value("${aliyun.oss.region}")
// private String region ;
//方式二:
@Autowired
private AliyunOSSProperties aliyunOSSProperties;
public String upload(byte[] content, String originalFilename) throws Exception {
String endpoint = aliyunOSSProperties.getEndpoint();
String bucketName = aliyunOSSProperties.getBucketName();
String region = aliyunOSSProperties.getRegion();
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Object完整路径,例如202406/1.png。Object完整路径中不能包含Bucket名称。
//获取当前系统日期的字符串,格式为 yyyy/MM
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
//生成一个新的不重复的文件名
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = dir + "/" + newFileName;
// 创建OSSClient实例。官方代码
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
} finally {
ossClient.shutdown();
}
return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
}
}
删除员工
@DeleteMapping
public Result delete(@RequestParam List<Integer> ids){
log.info("批量删除员工:{}", ids);
empService.delete(ids);
return Result.success();
}
@Transactional(rollbackFor = {Exception.class})
@Override
public void delete(List<Integer> ids) {
//删除员工的基本信息
empMapper.deleteByIds(ids);
//删除员工的工作经历信息
empExprMapper.deleteByEmpIds(ids);
}
<?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.itheima.mapper.EmpExprMapper">
<!-- 批量保存员工工作经历
foreach:
collection:遍历的集合
item:遍历出来的元素的名字
separator:每次循环之间的分隔符
-->
<insert id="insertBatch">
insert into emp_expr(emp_id, begin, end, company, job) VALUES
<foreach collection="exprList" item="expr" separator=",">
(#{expr.empId},#{expr.begin},#{expr.end},#{expr.company},#{expr.job})
</foreach>
</insert>
<delete id="deleteByEmpIds">
delete from emp_expr where emp_id in
<foreach collection="empIds" item="Id" separator="," open="(" close=")">
#{Id}
</foreach>
</delete>
</mapper>
<?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.itheima.mapper.EmpMapper">
<!-- 批量删除员工的基本信息-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<select id="list" resultType="com.itheima.pojo.Emp">
select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id
<where>
<if test="name != null and name != ''">
e.name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and e.gender = #{gender}
</if>
<if test="begin != null and end != null">
and entry_date between #{begin} and #{end}
</if>
</where>
order by e.update_time desc
</select>
</mapper>
Spring 对List类型的参数,无论参数名是否一致,都必须显式添加@RequestParam注解才能完成绑定,不存在 “省略注解也能生效” 的情况。下面详细拆解原因和修正方案。
一、为什么这段代码不加注解会失效?
-
Spring 的参数绑定规则限制
Spring 的无注解自动绑定仅支持基本类型、包装类、String、数组等「简单类型」,而
List是集合容器类型,不在自动绑定的范围内。即使参数名names与前端传入的参数名完全一致,Spring 也无法识别 “将请求中的names参数封装为List<String>”,最终入参names会是null。 -
实际运行的表现
若执行这段代码,前端请求
/list?names=张三&names=李四,后端接收到的names值为null,返回结果会是List参数:null,而非预期的List参数:[张三, 李四]。
二、正确的写法(必须加@RequestParam)
想要让List<String> names正确绑定前端参数,必须显式添加@RequestParam注解,这是唯一的正确方式:java运行
@GetMapping("/list")
public String getList(@RequestParam List<String> names) {
return "List参数:" + names;
}
此时前端请求/list?names=张三&names=李四,后端才能正确接收并封装为List<String>,返回List参数:[张三, 李四]。
三、容易混淆的 “例外情况”:数组类型可省略注解
如果将入参改为数组类型String[] names,则可以省略@RequestParam,因为数组属于 Spring 的「简单类型」,支持无注解自动绑定:java运行
// ✅ 数组类型:参数名一致,可省略@RequestParam,绑定正常
@GetMapping("/list")
public String getList(String[] names) {
return "数组参数:" + Arrays.toString(names);
}
前端请求/list?names=张三&names=李四,会返回数组参数:[张三, 李四],这是数组与 List 的核心区别,也是最容易产生误解的点。
修改员工
- 查询回显
- 修改数据
<?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.itheima.mapper.EmpMapper">
<!-- 批量删除员工的基本信息-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<select id="list" resultType="com.itheima.pojo.Emp">
select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id
<where>
<if test="name != null and name != ''">
e.name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and e.gender = #{gender}
</if>
<if test="begin != null and end != null">
and entry_date between #{begin} and #{end}
</if>
</where>
order by e.update_time desc
</select>
<!-- 定义resultMap-->
<resultMap id="empResultMap" type="com.itheima.pojo.Emp">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="phone" property="phone"/>
<result column="job" property="job"/>
<result column="salary" property="salary"/>
<result column="image" property="image"/>
<result column="entry_date" property="entryDate"/>
<result column="dept_id" property="deptId"/>
<result column="create_time" property="createTime"/>
<!-- 封装工作经历-->
<collection property="exprList" ofType="com.itheima.pojo.EmpExpr">
<id column="ee_id" property="id"/>
<result column="ee_empid" property="empId"/>
<result column="ee_begin" property="begin"/>
<result column="ee_end" property="end"/>
<result column="ee_company" property="company"/>
<result column="ee_job" property="job"/>
</collection>
</resultMap>
<!-- 根据ID查询员工的基本信息和员工基本工作经历信息-->
<select id="getById" resultMap="empResultMap">
select
e.*,
ee.id ee_id,
ee.emp_id ee_empid,
ee.begin ee_begin,
ee.end ee_end,
ee.company ee_company,
ee.job ee_job
from emp e left join emp_expr ee on e.id = ee.emp_id
where e.id =#{id};
</select>
</mapper>
@PutMapping
public Result update(@RequestBody Emp emp){
log.info("修改员工:{}",emp);
empService.update(emp);
return Result.success(emp);
}
/**
* 修改员工
* @param emp
*/
@Transactional(rollbackFor = {Exception.class})
@Override
public void update(Emp emp) {
//1.根据ID修改员工的基本信息
emp.setUpdateTime(LocalDateTime.now());
empMapper.updateById(emp);
//2.根据ID修改员工的工作经历信息
//2.1先根据员工ID删除原有的工作经历
empExprMapper.deleteByEmpIds(Arrays.asList(emp.getId()));
//2.2再添加
List<EmpExpr> exprList = emp.getExprList();
if (!CollectionUtils.isEmpty(exprList)){
exprList.forEach(empExpr -> {
empExpr.setEmpId(emp.getId());
});
empExprMapper.insertBatch(exprList);
}
}
优化
动态SQL
<!-- 根据ID更新员工基本工作经历信息-->
<!-- set标签:mybatis中动态标签:自动生成set关键字;会自动删除掉更新字段后多余的逗号-->
<update id="updateById">
UPDATE emp
<set>
<if test="username != null and username != ''">username = #{username},</if>
<if test="password != null and password != ''">password = #{password},</if>
<if test="name != null and name != ''">name = #{name},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="phone != null and phone != ''">phone = #{phone},</if>
<if test="job != null">job = #{job},</if>
<if test="salary != null">salary = #{salary},</if>
<if test="image != null and image != ''">image = #{image},</if>
<if test="entryDate != null">entry_date = #{entryDate},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="updateTime != null">update_time = #{updateTime}</if>
</set>
WHERE id = #{id}
</update>
动态SQL标签
:自动删掉多余逗号;自动生成set关键字 :自动删掉and和or

浙公网安备 33010602011771号