SpringBoot实战3
一、展示文章列表(根据条件进行分页)
Controller层:
通过PageBean的实体对象将对应的分页信息作为Result结果展示出来
@RequestParam(required = false) Integer categoryId
说明的是这个参数不是必须的
//TODO:文章条件分页查询
@GetMapping
public Result<PageBean<Article>> list(Integer pageNum,Integer pageSize,@RequestParam(required = false) Integer categoryId,@RequestParam(required = false) String state
){PageBean<Article> pageBean=articleService.list(pageNum,pageSize,categoryId,state);return Result.success(pageBean);
}
引入实体PageBean的创建
//分页返回结果对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean <T>{private Long total;//总条数private List<T> items;//当前页数据集合
}
Service层:
1、创建PageBean对象用于返回结果
2、使用PageHelper插件开启分页查询并且导入对应的依赖
PageHelper.startPage(pageNum,pageSize);
参数一为需要查询的页码,参数二为查询的条数
<!--分页的插件-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.7</version>
</dependency>
3、调用mapper查询分页数据(UserId从ThredLocal中获取)返回为一个List<Article>
List<Article> articles =articleMapper.list(userId,categoryId,state);
4、通过Page中的方法获取PageHelper分页查询之后的总记录数和当前页的数据
Page<Article> page= (Page<Article>) articles; //TODO:设置pageBean的属性,将数据封装到pageBean中 pageBean.setTotal(page.getTotal()); pageBean.setItems(page.getResult());
@Override
public PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state) {//TODO:创建pageBean对象PageBean<Article> pageBean=new PageBean<>();//TODO:开启分页查询PageHelper.startPage(pageNum,pageSize);//TODO:调用mapper查询分页数据Map<String, Object> map = ThreadLocalUtil.get();Integer userId= (Integer) map.get("id");List<Article> articles =articleMapper.list(userId,categoryId,state);//TODO:通过Page中的方法获取PageHelper分页查询之后的总记录数和当前页的数据Page<Article> page= (Page<Article>) articles;//TODO:设置pageBean的属性,将数据封装到pageBean中pageBean.setTotal(page.getTotal());pageBean.setItems(page.getResult());return pageBean;
}
Mapper层:由于参数categoryId,参数state可以写也可以不写,那么可以使用动态SQL的形式进行查询操作—》书写对应的Mapper映射文件
List<Article> list(Integer userId, Integer categoryId, String state);
com/example/mapper/ArticleMapper.xml
<!--mapper namespace属性为对应的Mapper类-->
<mapper namespace="com.example.mapper.ArticleMapper"><!--书写对应的list方法要执行的动态SQL--><select id="list" resultType="com.example.pojo.Article">select * from article<where><if test="categoryId != null">category_id = #{categoryId}</if><if test="state != null">and state = #{state}</if><if test="userId != null">and create_user = #{userId}</if></where></select>
</mapper>
二、获取文章详情
Controller层:
//TODO:获取文章详情
@GetMapping("/detail")
public Result<Article> detail(@RequestParam Integer id){Article article=articleService.detail(id);return Result.success(article);
}
Service层:
@Override
public Article detail(Integer id) {return articleMapper.detail(id);
}
Mapper层:
@Select("select * from article where id=#{id}")
Article detail(Integer id);
三、修改文章
Controller层:对于传入的实体对象参数进行参数校验通过分组校验
的形式进行
//TODO:修改文章
@PutMapping
public Result update(@RequestBody @Validated(Article.Update.class) Article article){articleService.update(article);return Result.success();
}
定义分组校验的实现–》在article中
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Article {@NotNull(groups = {Update.class})private Integer id;//主键ID@NotEmpty//1~10个非空字符@Pattern(regexp = "^\\S{1,10}$",groups = {Add.class})private String title;//文章标题@NotEmptyprivate String content;//文章内容@NotEmpty@URL(groups = {Add.class})private String coverImg;//封面图像@NotEmpty//状态只能为已发布或者草稿//@Pattern(regexp = "^(已发布|草稿)$")@Stateprivate String state;//发布状态 已发布|草稿@NotNullprivate Integer categoryId;//文章分类idprivate Integer createUser;//创建人IDprivate LocalDateTime createTime;//创建时间private LocalDateTime updateTime;//更新时间public interface Add extends Default{}public interface Update extends Default{}
}
Service层:
@Override
public void update(Article article) {//更新文章时间article.setUpdateTime(LocalDateTime.now());articleMapper.update(article);
}
Mapper层:
@Update("update article set title=#{title},content=#{content},cover_img=#{coverImg},state=#{state},category_id=#{categoryId},update_time=#{updateTime} where id=#{id}")
void update(Article article);
四、删除文章
Controller层:
//TODO:删除文章
@DeleteMapping
public Result delete(@RequestParam Integer id){articleService.delete(id);return Result.success();
}
Service层
@Override
public void delete(Integer id) {articleMapper.delete(id);
}
Mapper层:
@Delete("delete from article where id=#{id}")
void delete(Integer id);
五、文件上传
关于文件上传的操作前端需要实现的部分是
1、提交方式为**Post
**
2、提交的表单类型为**multipart/form-data
**
3、表单项的类型为**file
**
后端通过**MultipartFile
类作为请求的参数**来实现文件上传操作
FileUploadController:将图片上传到本地transferTo(转存为一个新的图片文件)
@RestController
public class FIleUploadController {@PostMapping("/upload")public Result<String> upload(MultipartFile file) throws IOException {//TODO:将文件内容存储到本地磁盘上// TODO:获取文件名String originalFilename=file.getOriginalFilename();// TODO:需要保证文件名不重复--》防止文件因为重名而被覆盖// TODO:获取文件后缀--截取点后面的文件类型String endName=originalFilename.substring(originalFilename.lastIndexOf("."));String fileName= UUID.randomUUID().toString()+endName;file.transferTo(new File("D:\\桌面\\课程\\workspace\\big-event\\files\\"+fileName));return Result.success("url访问地址");}
}
将图片上传到阿里云–云端服务器,这样就能在网页直接访问图片了
OSS对象储存服务(可以通过网络在线存储和调用文本,图片,音频,视频等各种文件)
云服务通用思路
一、准备工作
- 注册登录实名认证
- 服务充值
- 开通对象存储服务(OSS)
- 创建Bucket(存储空间–》存储对象,文件的容器)
- 获取AccessKey(密钥)–》携带密钥进行上传
二、参照官方的SDK(软件开发工具包)编写入门程序
public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华北2(北京)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-beijing.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。//EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();String ACCESS_KEY_ID = "yourKeyId";String ACCESS_KEY_SECRET = "yourKeySecret";// 使用DefaultCredentialProvider方法直接设置AK和SKCredentialsProvider credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);// 填写Bucket名称,例如examplebucket。String bucketName = "geishihua-big-event";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如001.pngString objectName = "001.png";// 填写Bucket所在地域。以华北2(北京)为例,Region填写为cn-beijing。String region = "cn-beijing";// 创建OSSClient实例。ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);OSS ossClient = OSSClientBuilder.create().endpoint(endpoint).credentialsProvider(credentialsProvider).clientConfiguration(clientBuilderConfiguration).region(region).build();try {// 填写字符串。String content = "Hello OSS,你好世界";// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new FileInputStream("D:\\桌面\\课程\\springboot3+Vue3\\imgs\\4.png"));// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传字符串。PutObjectResult result = ossClient.putObject(putObjectRequest);} 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上传的功能集成为一个工具类AliOssUtil
public class AliOssUtil {// Endpoint以华北2(北京)为例,其它Region请按实际情况填写。endpoint在这个bucket的概览处中的访问端口的外网访问一栏private static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";// 填写您的AccessKey ID和AccessKey Secret。private static final String ACCESS_KEY_ID = "yourId";private static final String ACCESS_KEY_SECRET = "yourSecret";// 填写Bucket名称,例如examplebucket。private static final String BUCKET_NAME = "yourbucketname";// 填写Bucket所在地域。以华北2(北京)为例,Region填写为cn-beijing。private static final String REGION = "cn-beijing";public static String UploadFile(String objectName, InputStream in) throws Exception {// 使用DefaultCredentialProvider方法直接设置AK和SKCredentialsProvider credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);// 创建OSSClient实例。ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);OSS ossClient = OSSClientBuilder.create().endpoint(ENDPOINT).credentialsProvider(credentialsProvider).clientConfiguration(clientBuilderConfiguration).region(REGION).build();String url="";try {// 填写字符串。String content = "Hello OSS,你好世界";// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, objectName, in);// 上传字符串。PutObjectResult result = ossClient.putObject(putObjectRequest);// 获取上传文件的URL组成:http://BUCKET_NAME.oss-cn-beijing.aliyuncs.com/OBJECT_NAMEurl = "http://" + BUCKET_NAME + ".oss-" + REGION+".aliyuncs.com" + "/" + objectName;} 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();}}return url;}
}
改写将文件上传到本地
@RestController
public class FIleUploadController {@PostMapping("/upload")public Result<String> upload(MultipartFile file) throws Exception {//TODO:将文件内容存储到本地磁盘上// TODO:获取文件名String originalFilename=file.getOriginalFilename();// TODO:需要保证文件名不重复--》防止文件因为重名而被覆盖// TODO:获取文件后缀--截取点后面的文件类型String endName=originalFilename.substring(originalFilename.lastIndexOf("."));String fileName= UUID.randomUUID().toString()+endName;//file.transferTo(new File("D:\\桌面\\课程\\workspace\\big-event\\files\\"+fileName));//TODO:通过MultipartFile获取文件流--file.getInputStream()String url = AliOssUtil.UploadFile(fileName, file.getInputStream());return Result.success(url);}
}