当前位置: 首页 > news >正文

Day47(17)-F:\硕士阶段\Java\课程代码\后端\web-ai-code\web-ai-project02

文件上传

服务器搭建

image-20251124131949006

云服务

image-20251124132052428

image-20251124132218894

image-20251124132551370

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集

image-20251124142322620

image-20251124142401623

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/MMString 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();
//    }@Autowiredprivate 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);}
}

image-20251124151437001

image-20251124151642118

#阿里云OSS
aliyun:oss:endpoint: https://oss-cn-beijing.aliyuncs.combucketName: java-ai-01-davidregion: 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/MMString 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;}}

image-20251124152520710

image-20251124152632534

image-20251124153020232

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 ;//方式二:@Autowiredprivate 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/MMString 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;}}

image-20251124153707914

删除员工

image-20251124154052815

@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 mapperPUBLIC "-//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 mapperPUBLIC "-//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注解才能完成绑定,不存在 “省略注解也能生效” 的情况。下面详细拆解原因和修正方案。

一、为什么这段代码不加注解会失效?

  1. Spring 的参数绑定规则限制

    Spring 的无注解自动绑定仅支持基本类型、包装类、String、数组等「简单类型」,而List集合容器类型,不在自动绑定的范围内。即使参数名names与前端传入的参数名完全一致,Spring 也无法识别 “将请求中的names参数封装为List<String>”,最终入参names会是null

  2. 实际运行的表现

    若执行这段代码,前端请求/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 的核心区别,也是最容易产生误解的点。

image-20251124163513366

修改员工

  1. 查询回显
  2. 修改数据

image-20251124165159019

image-20251124170829269

image-20251124171233043

image-20251124171613175

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//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">selecte.*,ee.id ee_id,ee.emp_id ee_empid,ee.begin ee_begin,ee.end ee_end,ee.company ee_company,ee.job ee_jobfrom emp e left join emp_expr ee on e.id = ee.emp_idwhere e.id =#{id};</select>
</mapper>

image-20251124173549125

image-20251124174309563

@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

image-20251124181325226

<!--    根据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标签

  1. :自动删掉多余逗号;自动生成set关键字
  2. :自动删掉and和or

image-20251124182757416

异常管理

信息统计

http://www.jsqmd.com/news/49678/

相关文章:

  • 国内可靠的清障车品牌排行,折臂高空作业车/拖吊联体清障车/云梯高空作业车/蓝牌清障车/二手蓝牌平板拖车/高空作业车清障车专业厂家选哪家
  • 2025年本地好评恒温恒湿箱品牌TOP10,砂尘试验箱/盐水喷雾试验箱及各种老化房/恒温恒湿试验箱/高低温交变量热试验箱恒温恒湿箱公司推荐
  • 2025年11月GEO优化公司推荐优选指南:专业分析维度助力企业精准决策
  • 开题报告模板详解:手把手教你写出完美开题报告
  • 题解:CF2157D Billion Players Game
  • 2025年11月GEO优化服务商推荐报告:从稳定性到AI能力的解决方案剖析
  • 联通退订一些服务
  • 2025-11-24
  • NewStarCTF2024 Week4 Pwn MakeHero
  • 噬菌体筛选:纳米抗体阳性克隆富集的核心实验技术
  • 2025年11月GEO优化公司推荐热度榜:基于十大性能指标的结果承诺保障方案
  • 2025年11月GEO服务商推荐选择指南:专业分析维度助力企业的精准决策
  • SQL-leetcode—3475. DNA 模式识别 - 详解
  • 「张张讲AI」AI资讯公众号:联动深圳人才集团,讲师输出资讯+授课,助力AI落地
  • 使用frp实现内网穿透
  • 2025年11月GEO优化公司推荐权威榜单:十大品牌核心价值与解决方案解析
  • 2025年11月GEO公司推荐选择指南:专业分析维度助力企业精准决策
  • 2025年11月GEO服务商推荐评测报告:从稳定性到AI能力解决方案剖析
  • 2025年11月GEO优化服务商推荐评测报告:从技术实力到实战成果的解决方案剖析
  • macOS怎么关闭指定软件的开机自启
  • WPF的四种曲线绘制
  • 2025年11月北京陪诊公司推荐榜:专业机构服务对比与选择指南
  • 2025年11月北京陪诊公司推荐榜:专业服务对比与用户口碑分析
  • 2025.11.24 - A
  • Codeforces 1473E Minimum Path 题解 [ 蓝 ] [ 分层图最短路 ] [ 贪心 ] [ 构造 ]
  • AI医疗应用研究项目获奖公布
  • 11.24每日总结
  • 别让你的SQL跑了一整晚,最后只产出一堆数字垃圾
  • 二分图边着色学习笔记
  • 2025年11月四川软电线/硬芯线/家装电线/铝合金电缆/铝芯电缆/铜芯/高压/中压/低压电线电缆供应厂家综合推荐指南:五大优质厂商深度解析