你好,我是Qiuner. 为记录自己编程学习过程和帮助别人少走弯路而写博客 这是我的 github gitee
如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 😄 (^ ~ ^)
想看更多 那就点个关注吧 我会尽力带来有趣的内容
有没出现的图片 请访问 传送门 这是我的掘金账号 掘金文档的图片图片上传做的很好,欢迎关注我的掘金账号 😍
快速入门Web开发(下)
案列开发
部分详情见 文件 JavaWeb案列
- 没写去全,想知道全部就去看JavaWeb案列,一定要去看
限定请求方式
//方案一
@RequestMapping (value = "/depts",method = RequestMethod.GET)//限定请求方式为get
//限定请求方式为get
//不需要打出value,写路径后,直接写method=请求类型就好
//方案二
@GetMapping ("/depts")
public Result list(){
log.info("查询全部部门数据");
return Result.success();
}
开发部门相应功能
基本的开发方式及查询所有部门
- 开发一个小的需求的时候,先看对接文档
比如,开发该需求,查询全部的部门数据先分析
- 接口文档中注明了请求类型和请求地址
理清以上后,开始写代码
代码要实现的是
这三件事情。但我们需要将其分在不同的文件夹及java文件中。
-
在dao层(mapper)中进行数据访问
-
在service层中进行逻辑处理
-
在controller层中接收请求,响应数据
-
pojo是存放对象的地方,比如检验是否成功的Result
流程是这样的:前端发送请求之后先进入到controller中的部门表(因为对部门进行操作),而该项会调用service来获取数据,在service中调用了mapper接口中的方法来查询信息,而mapper会对数据库进行操作,并将信息封住在list集合当中,将数据返回给service然后返回给controller最后返回给前端
- 因为使用的是json格式,所以使用list集合
为什么没有创建相应对象却能够在几个不同的文件中互相调用,返回?
因为使用了依赖注入!
在 list()
方法中,通过调用 deptMapper.list()
来执行查询操作,并将查询结果作为方法的返回值。这里的 deptMapper.list()
就是调用 DeptMapper
接口的 list()
方法,从数据库中获取部门数据。
虽然代码中没有直接写出 DeptMapper
的调用,但通过依赖注入的方式,DeptMapper
实例已经被注入到了 deptMapper
字段中,可以在 list()
方法中通过 deptMapper
字段来调用 DeptMapper
的方法。
删除部门
@DeleteMapping("/depts/{id}")
public Result delete(@PathVariable Integer id){
//使用以下写法可以,将{}替换成id
log.info("删除部门数据:{}",id);
List<Dept> deptList =deptService.delete();
return Result.success(deptList);
}
@PathVariable
是一个Spring框架的注解,用于从URL路径中提取变量的值,并将其绑定到方法参数上。在你提供的代码中,
@PathVariable Integer id
表示使用@PathVariable
注解将URL路径中的变量值绑定到方法参数id
上。具体来说,当请求的URL路径为 “/depts/{id}”,例如 “/depts/123”,
@DeleteMapping("/depts/{id}")
注解表示这是一个用于处理HTTP DELETE请求的处理方法,并且路径中的{id}
部分将被解析为方法参数id
新增部门
@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.add(dept);
}
补充属性指需要补充的属性
比如这里,前端传给我们其他参数,但修改时间和进入时间是我们来决定的,因此需要在这里增加
使用@RequestMapping优化
如何分辨使用注解获取服务器发过来的数据?(重点)
当请求数据是以下这样时(json格式)
{
"id": 1,
"name": "教研部"
}
- 是一个请求体数据,要使用能将请求体数据绑定的注解来实现
当请求数据是以下这样时(写在导航栏上),要使用能将请求的URL中提取路径参数的注解来实现
/depts/1
详情见http笔记
更新部门
- 在这个工程中更新部门需要点两次
- 先点击编辑弹出页面,输入修改的name属性。这个过程就执行了一次查询操作
- 然后点击确定,将修改好的name属性传递给后端
开发员工表相应功能
分页查询
- 详细要求去看相应api接口文档
- 接收参数需要默认值的时候,可以使用以上两种方式设置
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=new PageBean(count,empList);
return pageBean;
}
- 遇到多个数据时候,将其封装成一个对象来传输
PageHelper插件
- 该插件使用PageHelper对象进行操作
以下是使用 PageHelper
进行分页查询的一般步骤:
- 在项目的依赖管理中引入
PageHelper
的相关依赖,通常需要包括pagehelper-core
和mybatis-spring-boot-starter
。 - 在 MyBatis 的配置文件中,配置
PageInterceptor
作为拦截器。这样,PageHelper
就能够拦截查询语句,自动实现分页功能。 - 在需要进行分页查询的方法中,直接使用
PageHelper.startPage(pageNum, pageSize)
来设置当前页码和每页显示的记录数。 - 执行查询操作,
PageHelper
会自动进行分页处理,并返回一个包含分页结果的PageInfo
对象。
- 插件原理
在执行empMapper.list()方法时,就是执行:select * from emp 语句,怎么能够
实现分页操作呢?
分页插件帮我们完成了以下操作:
- 先获取到要执行的SQL语句:select * from emp
- 把SQL语句中的字段列表,变为:count(*)
- 执行SQL语句:select count(*) from emp //获取到总记录数
- 再对要执行的SQL语句:select * from emp 进行改造,在末尾添加 limit ? ,
?
- 执行改造后的SQL语句:select * from emp limit ? , ?
- 使用中的第一条,调用插件中的本体方法来设置分页参数
- 第二条通过插件将该条变成分页查询语句
//方式一:service层
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=new PageBean(count,empList);
return pageBean;
}
//dao层
//查询总记录
@Select("select count(*) from webcase.emp")
public Long count();
// 分页查询列表数据
@Select("select * from webcase.emp limit #{start},#{pageSize}")
public List<Emp> page(Integer start,Integer pageSize);
//方式一:service层(使用插件)
public PageBean page(Integer page, Integer pageSize) {
//设置分页参数
PageHelper.startPage(page, pageSize);
//获取数据
List<Emp> empList= empMapper.list();
Page<Emp> p=(Page<Emp>) empList;
// 封装成对象
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}
//dao层
/*员工信息查询(使用插件)*/
@Select("select * from webcase.emp")
public List<Emp> list();
}
//(其中Emp用于接收传递的数据)
条件分页查询
- 后面还有新增员工和删除员工就不多赘述了
- 文件上传前端三要素
- 请求方式为post,要有file,特殊的编码格式
文件上传
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
//使用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>
</body>
</html>
- 生成临时文件来上传,上传后将文件删除
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String name, Integer age, MultipartFile image) throws IOException {
log.info("接收到的参数name:{},age:{},image:{}",name,age,image);
// 获取文件的原始名
String originalFilename= image.getOriginalFilename();
// 产生的临时文件保存在本地E:\image
image.transferTo(new File("E:\\image\\"+originalFilename ));
return Result.success();
}
}//这样写,有一个明显的问题:后来的同名文件会替代原本的文件
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String name, Integer age, MultipartFile image) throws IOException {
log.info("接收到的参数name:{},age:{},image:{}",name,age,image);
// 获取文件的原始名
String originalFilename= image.getOriginalFilename();
int index=originalFilename.lastIndexOf(".");//找到文件名最后.的位置
String extname=originalFilename.substring(index);//截取字符
//使用uuid创建文件名
String newFileName= UUID.randomUUID().toString()+extname;
// 产生的临时文件保存在本地E:\image
image.transferTo(new File("E:\\image\\"+newFileName ));
return Result.success();
}
}
- 在application.properties中配置
使用云来存储图片
private AliOSSUtils aliOSSUtils;
/* 使用阿里云来上传图片 */
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
log.info("文件上传,文件原始名:{}",image.getOriginalFilename();
/* 使用工具来将文件上传,并获得该文件的网络地址 */
String url= aliOSSUtils.upload(image);
log.info("文件上传的地址:{}",url);
return Result.success(url);
}
@Component
public class AliOSSUtils {
//工具类
private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private String accessKeyId = "LTAI5tJcyLUHaXqJiTaw74Rd";
private String accessKeySecret = "mwRBKzxPC0BHFEwqQHZvCtvvlOIpho";
private String bucketName = "web-tlias-ww";
/**
* 实现上传图片到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的路径返回
}
}
在postman中测试上传
- 选择Body中的form—data,在key中选择Filr
使用不同配置文件优化
使用@ConfigurationProperties代码再优化
登录
// 登录接口
@Slf4j
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("用户登录:{}",emp);
// 登录
Emp emp1= empService.Login(emp);
return emp1!=null?Result.success():Result.error("用户名或秘密错误");
}//多了此项步骤,其他都一样
}
登录校验
会话技术
- Cookie技术
- Session技术
JWT
过滤器Filter
- 出现的意义是因为校验这个操作每个访问的资源页都需要出现一次且代码相同,于是使用过滤器
- 还要再启动文件中增加@ServletComponentScan来启动拦截服务
执行流程
过滤链
令牌校验
package com.example.webcase.filter;
import com.alibaba.fastjson2.JSONObject;
import com.example.webcase.pojo.JwtUtils;
import com.example.webcase.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*")//要拦截的请求
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 获取请求的url来进行判断
HttpServletRequest req= (HttpServletRequest) servletRequest;//请求对象()客户端给服务器(会带令牌)
HttpServletResponse resp= (HttpServletResponse) servletResponse;//响应对象
//获取url
String url =req.getRequestURI();
log.info("url:{}",url);
if (url.contains("login")){
log.info("登录");
filterChain.doFilter(servletRequest,servletResponse);
return;
}
// 获取token
String jwt= req.getHeader("token");
//判断token是否为空
if(!StringUtils.hasLength(jwt)){
log.info("未登入");
Result error= Result.error("NOT_LOGIN");
// 将数据转换为json格式
String notLogin= JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
/* 校验令牌,不通过会报错*/
try{
JwtUtils.parseJWT(jwt);
}catch (Exception e){
e.printStackTrace();
log.info("令牌解析失败");
/* 打印错误信息 */
Result error= Result.error("NOT_LOGIN");
String notLogin= JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
log.info("解析成功");
filterChain.doFilter(servletRequest,servletResponse);
}
}
拦截器
-
拦截器
-
使用@ServletComponentScan来开启对servlet组件的使用(在启动文件位置)(开启拦截器)
全局异常处理器
- 注释二用来指定捕获异常种类
事物回滚
#spring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
@Transactional
事物传播
AOP
- 没有文件名的要求,只需要引用依赖后,添加 @Aspect 注释,并使用切入点表达式添加范围即可
@Aspect来标注类是aop类
- 切入点可以理解为需要增强的方法
- 使用aop后是使用基于目标对象生成的代理对象来运行
通知类型
通知顺序
通过使用@Order来控制顺序
切入点表达式
annotation
-
定义一个注解,需要切入点需要在哪里就把该方法放在切入点上面
-
该注解使用时,括号内的是定义注解的位置
连接点
- 在方法中增加一个参数即可
案列
SpringBoot原理
配置文件的优先级
Bean
-
bean对象默认单列
-
springboot启动的时候loc容器就已经创建了,并实例化了对象放进了容器中
第三方Bean
- 自定义的使用@Component
- 第三方使用@Bean
为什么你能进行快捷的开发?
- 起步依赖和自动配置
Maven高级
模块
-
在父工程上添加项目的原本父工程后,然后将子工程原本的父工程换为新的换成父工程
-
每个项目生成后,都会有springboot这个父工程的依赖
版本控制
方法二
聚合
Maven私服
技术栈
ngboot这个父工程的依赖
[外链图片转存中…(img-srTvanTe-1714097487488)]
版本控制
[外链图片转存中…(img-1fjrsuCB-1714097487488)]
[外链图片转存中…(img-eJyFXN7D-1714097487489)]
方法二
[外链图片转存中…(img-uG5OywVK-1714097487489)]
[外链图片转存中…(img-YILjjxyY-1714097487489)]
聚合
[外链图片转存中…(img-J4HRjBp7-1714097487490)]
[外链图片转存中…(img-Qt14Y3mp-1714097487490)]
[外链图片转存中…(img-mcc9ErXb-1714097487490)]
Maven私服
[外链图片转存中…(img-ofB5rvaA-1714097487491)]
[外链图片转存中…(img-tboNSNwu-1714097487491)]
[外链图片转存中…(img-yljPDnR6-1714097487491)]
[外链图片转存中…(img-6wo47DZR-1714097487492)]
[外链图片转存中…(img-sxoIl0nB-1714097487492)]
[外链图片转存中…(img-mtHjlikK-1714097487492)]
技术栈
[外链图片转存中…(img-oHkLu4cp-1714097487493)]
[外链图片转存中…(img-YYRYXa8W-1714097487493)]
[外链图片转存中…(img-BznHyq6r-1714097487494)]
[外链图片转存中…(img-UFAU2REN-1714097487495)]
[外链图片转存中…(img-CNQzX3FA-1714097487496)]