SpringBoot个人学习笔记
SpringBoot
1注解常用知识点
@slj4
加在applicaiton()
就可以使用log.info()用于日志
@Resource
按名字注入
@Autowired
按类型注入
@RequestBody
1 |
|
接受前端页面传递过来的数据,根据同名字
而Body请求体只存在于POST请求
MD5加密
1 |
|
@Bean
@Bean是放在方法的注释上了,因为它很明确地告诉被注释的方法,你给我产生一个Bean,然后交给Spring容器,剩下的你就别管了
记住,@Bean就放在方法上,就是让方法去产生一个Bean,然后交给Spring容器。
1 |
|
不知道大家有没有想过,用于注册Bean的注解的有那么多个,为何还要出现@Bean注解?
原因很简单:类似@Component , @Repository , @ Controller , @Service 这些注册Bean的注解存在局限性,只能局限作用于自己编写的类,如果是一个jar包第三方库要加入IOC容器的话,这些注解就手无缚鸡之力了,是的,@Bean注解就可以做到这一点!当然除了@Bean注解能做到还有@Import也能把第三方库中的类实例交给spring管理,而且@Import更加方便快捷,只是@Import注解并不在本篇范围内,这里就不再概述。
使用@Bean注解的另一个好处就是能够动态获取一个Bean对象,能够根据环境不同得到不同的Bean对象
————————————————
版权声明:本文为CSDN博主「宜春」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44543508/article/details/103718958
在方法前注解
让spring在需要的时候,通过自行自动调用这个方法,自行自动创建对象,
Spring注解的理解
参考链接: https://blog.csdn.net/qq_44543508/article/details/103718958
一类注解是用于注册Bean比如@Component , @Repository , @ Controller , @Service , @Configration
1 |
|
一类注解是用于使用Bean
1 |
|
接口方法接收前端传入参数
传统方式—针对localhost:8080/shop?page=1
*如果是通过这种传送数据参数给后端
用的是@RequestParam
如果省略了也是默认@RequestParam,所以则可以直接(int page,int pageSize)即可
接口方法参数不使用任何注释:这其实也是默认使用的是Request.getParameter() 方法对参数进行获取的,只是没有显示使用@RequestParam而已,
1 |
|
也可以用@RequestParam
RESTFUL格式—-针对localhost:8080/10048
这样的加个@GetMapping(“/{id}”) @PathVariable也行
JSON方式—-针对POST方法的请求体
加@RequestBody
只有管理员(admin)才能看到启用,禁用按钮?非管理员看不见该按钮
下面是代码展示< v-if><>
可以利用v-if完成要求
出现
从userInfo中取出username,并赋值给user模型数据
判断模型数据user的值是否等于admin,若等于则显示按钮
当maven无法下载源代码时候执行
【检查方式maven正确情况下,再执行本步骤】则在项目下,项目根目录下 或 pom.xml同级目录中执行
mvn dependency:resolve -Dclassifier=sources
可能原因2:网络问题
1.没换源且没魔法上网
2.换了源又魔法上网
2.servlet,session,request,application
request是表示一个请求,只要发出一个请求就会创建一个request,它的作用域:仅在当前请求中有效。
用处:常用于服务器间同一请求不同页面之间的参数传递,常应用于表单的控件值传递。
方法:request.setAttribute(); request.getAttribute(); request.removeAttribute(); request.getParameter().
服务器会为每个会话创建一个session对象,所以session中的数据可供当前会话中所有servlet共享。
会话:用户打开浏览器会话开始,直到关闭浏览器会话才会结束。一次会话期间只会创建一个session对象。
用处:常用于web开发中的登陆验证界面(当用户登录成功后浏览器分配其一个session键值对)。
方法:session.setAttribute(); session.getAttribute(); session.removeAttribute();
获得session对象方法:
在Servlet中:HttpSession session = request.getSession();
由于session属于jsp九大内置对象之一,当然可以直接使用。例如:<%session.serAttribute(“name”,“admin”)%>。
session被销毁
1)session超时;
2)客户端关闭后,再也访问不到和该客户端对应的session了,它会在超时之后被销毁;
3)调用session. invalidate();
备注: session是服务器端对象,保存在服务器端。并且服务器可以将创建session后产生的sessionid通过一个cookie返回给客户端,以便下次验证。(session底层依赖于cookie)
作用范围:所有的用户都可以取得此信息,此信息在整个服务器上被保留。Application属性范围值,只要设置一次,则所有的网页窗口都可以取得数据。ServletContext在服务器启动时创建,在服务器关闭时销毁,一个JavaWeb应用只创建一个ServletContext对象,所有的客户端在访问服务器时都共享同一个ServletContext对象;ServletContext对象一般用于在多个客户端间共享数据时使用;
————————————————
版权声明:本文为CSDN博主「之前我没得选,现在我想做个好人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43368645/article/details/114382818
4.spring整合mybatis-plus
1.勾选mysql,然后手动pom添加(因为目前还没有更新)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
2.配置application.yml
1 |
|
BaseMapper<>
1 |
|
4.不用再写sql语句不用再写mapper,已经完成
通用service的IService
1 |
|
通用Impl的ServiceImpl
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}
java驼峰命名法,映射,数据库下划线命名法
1 |
|
过滤器Filter
1.编写Filter
@WebFilter(filterName = “” , urlPatterns = “/*”)//对所有的都先加入过滤器,后面再针对不同类选择是否直接放行
@slf4j
public class LoginCheckFilter implementes Filter{}
2.启动类加入写@ServletCOmponentScan
@ServletComponentScan
在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。
filterChain,doFilter(request,response)放行,进行下一个流程
1 |
|
新增员工Save方法
启动项目后,输入员工信息,点击保存
保存后,可以看到控制台上打印的数据,表示可以接收到前端传递到服务端的数据
这一串数据已经在前端打包好成为一个Employee了,是前端传过来的给服务器
通过Controller后端save方法,,实现将前端给定employee存入数据库
@PostMapping
public R<String> save(HttpServletRequest request, @RequestBody Employee employee){
log.info("新增员工的信息:{}",employee.toString());
//设置初始密码,需要进行md5加密
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//强转为long类型
Long empID = (Long)request.getSession().getAttribute("employee");
employee.setCreateUser(empID);
employee.setUpdateUser(empID);
employeeService.save(employee);
return R.success("添加员工成功");
}
Controller中调用了service
service利用了mapper使用数据库
全局异常处理器GlobalExcptionHandler
我们的程序进行异常捕获,通常有两种处理方式:
- 在Controller方法中加入try、catch进行异常捕获
- 使用异常处理器进行全局异常捕获(推荐使用第二种方式)
在common包下,建立GlobalExceptionHandler类,并添加exceptionHandler方法用来捕获异常,并返回结果
比如针对异常:
java.sql. SQLIntegrityConstraintViolationException: Duplicate entry ‘zhangsan’for key ‘idx_username
这个就可以将后端发生的excption通过R发送到前端
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody //java对象转为json格式的数据
@Slf4j
public class GlobalExceptionHandler
{
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler (SQLIntegrityConstraintViolationException exception){
log.error(exception.getMessage());
if (exception.getMessage().contains("Duplicate entry")){
String[] split = exception.getMessage().split(" ");
String msg = split[2] + "已存在";
return R.error(msg);
}
return R.error("unknown error");
}
}
分页
流程:
页面发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端
服务端Controller接收页面提交的数据并调用Service查询数据
Service调用Mapper操作数据库,查询分页数据
Controller将查询到的分页数据响应给页面
页面接收到分页数据并通过ElementUI的Table组件展示到页面上
1.配置mybatisplus分页插件,通过config
1 |
|
2.点击员工管理,前端页面发送的请求
在搜索框中输入员工姓名,前端页面发送的请求
所以在controller中就可以编写page方法来处理这个get请求
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
log.info("page = {}, pageSize = {}, name = {}",page,pageSize,name);
//构造分页构造器
Page pageInfo = new Page(page, pageSize);
//构造条件构造器
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
//添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
//添加排序添加
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询
employeeService.page(pageInfo,queryWrapper);
//返回结果
return R.success(pageInfo);
}
Page pageInfo = new Page(page,pageSize);
LambdaQuerWrapper
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo)
Wrapper-mybatisplus
//构建一个查询的wrapper
QueryWrapper<User> wrapper = new QueryWrapper<User>();
//加入条件
//name不为空时,组装模糊查询条件
wrapper.like(StringUtils.isNotBlank(name),"name",name);
//未删除
wrapper.eq("del_flag",0);
//创建时间降序
wrapper.orderByDesc("create_time");
//执行查询
List<User> list = userMapper.selectList(wrapper);
分页
1 |
|
RESTFUL风格
@GetMapping,处理get请求
@PostMapping,处理post请求
@PutMapping,处理put请求
@DeleteMapping,处理delete请求
4.过滤器Filter
生命周期:伴随web启动而init,web停止而destory
filterchain.doFilter()将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源
// 让程序继续往下访问用户的目标资源
1 |
|
匹配URL路径
1 |
|
1 |
|
5.拦截器Inteceptor
2.在config注册
@ResponseBody与response.getWriter().write()
@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象,通常我们使用用来返回JSON数据或者是XML数据
前端页面:我这里使用的是ajax提交,指定dataType为json,接收到后台传来的数据会转为json对象
**对于response.getWriter().write(JSSONObject.toJSON())**的效果
效果也差不多
@RestController
@Controller和@ResponseBody(加在方法/类上面)一起使用 == @RestController的作用相同。
在mysql就可以设置属性为不可重复性Unique
如果存入重复数据username则会报错
F12查看network
可以看见发送到URL请求
MybatisPlus-分页
1.加入config的
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
2.分页得到的数据在page.getRecords()中
@Test
public void testSelectPage(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age", 18); // 年龄等于18
Page<User> page = new Page<>(1, 5); //当前页为1,每页5条
Page<User> pageParam = userMapper.selectPage(page, null); //第二个参数:实体对象封装操作类,如果没有可以为空
List<User> records = pageParam.getRecords(); //获取总记录列表
records.forEach(System.out::println); //遍历
System.out.println(pageParam.getPages());//总页数
System.out.println(pageParam.getTotal());//总记录数
System.out.println(pageParam.getCurrent());//当前页码
System.out.println(pageParam.getSize());//每页记录数
System.out.println(pageParam.hasNext());//是否有下一页
System.out.println(pageParam.hasPrevious());//是否有上一页
}
//执行查询
employeeService.page(pageInfo,queryWrapper);
公共字段自动填充
1.在实体类需要自动填充的属性加入@TableFIled
1 |
|
2编写类MyMetaObjectHandler implements MetaObjectHanlder
记得加入@Component
1 |
|
1.对象映射器
JacksonObjectMapper作用就是在后端controller返回response给前端网页时候,将java对象转为json对象传回
1 |
|
2.在config替换
1 |
|
提示报错:java: 找不到符号
解决方式clean和package
元数据(Metadata)
典型的元数据(Metadata)元素:
- 标题和描述
- 标签和分类
- 谁生成的,何时生成的
- 最后一次是被谁更改的,何时更改的
- 谁能访问或者更新
关于客户端的http请求与线程
同一个http请求是同一个线程
比如我点击保存,发送请求,会有三个流程loginCheckFilter过滤器,EmployeeCOntroller,MyMetaObjectHandler
ThreadLocal就是在一个线程中用于保存的局部变量
前置知识
Favicon.ico是自动成为网页图标
@RestController=@Contreller+@Responsebody
@ResponseBody
注解是将返回的数据结构转换为 Json 格式
所以@RestContreller也可以使得返回Json格式数据
Json
后端java对象 《—-》前端Json
SpringBoot处理JSON数据时,需要用到两个重要的JSON转换注解,分别是@RequestBody和@ResponseBody。
@RequestBody:将请求主体的数据绑定到形参上,该注解应用在方法的形参上
@ResponseBody:直接返回Json对象,该注解应用在方法上。
通过@ResponseBody和@RequestBody
后端对象: new User(1, “倪升武”, “123456”);
——-》
前端json {“id”:1,”username”:”倪升武”,”password”:”123456”}
@RestController
@RequestMapping("/json")
public class JsonController {@RequestMapping("/user")
public User getUser() {
return new User(1, "倪升武", "123456");
}
@RequestMapping("/list")
public List<User> getUserList() {
List<User> userList = new ArrayList<>();
User user1 = new User(1, "倪升武", "123456");
User user2 = new User(2, "达人课", "123456");
userList.add(user1);
userList.add(user2);
return userList;
}
@RequestMapping("/map")
public Map<String, Object> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1, "倪升武", "123456");
map.put("作者信息", user);
map.put("博客地址", "http://blog.itcodai.com");
map.put("CSDN地址", "http://blog.csdn.net/eson_15");
map.put("粉丝数量", 4153);
return map;
}
前端
@RequestMapping
是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。
@RequestMapping(value=”/test”)
value可省略
@RequestMapping(“/test”)
@RequestMapping(value=”/test”,method = RequstMethod.GET)
@GetMapping(“/test”)
@PathVariable
@PathVariable
注解主要是用来获取 url 参数,Spring Boot 支持 restfull 风格的 url,比如一个 GET 请求携带一个参数 id 过来,我们将 id 作为参数接收,可以使用 @PathVariable
注解
实例:
localhost:8080/test/user/2/zhangsan
1 |
|
1 |
|
1 |
|
@RequestParam
实例:
1 |
|
1 |
|
注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。
请求体只有一个,@RequestBody最多只能有一个请求体
而@RequestParam()可以有多个。
@RequestBody –> JSON字符串部分
@RequestParam –> 请求参数部分
application/json格局图
form-data、x-www-form-urlencoded格局图
@RequestBody
get请求没有请求体不能用requestbody
自定义参数封装过程原理【用实体类接收参数】
@RequestBody,get请求的url参数传入等可以接收前端传来的多个参数,然后Controller方法中会使得其自动封装为一个实体类
在使用ajax发送请求时,如果发送的JSON数据是一个类中的不同属性,在Controller方法中使用@RequestBody会直接封装进该类中
实例:
传来同一个类的多个参数
User
1 |
|
前端传来————此时ajax提交的JSON数据为
1 |
|
后端接受—————-就可以直接@RequestBody
1 |
|
问题:SpringBoot框架下,控制层代码接受前台传递的参数,使用注解@RequestBody接受时,用实体作为接受参数,实体接受不到参数。新增时,报sql空数据异常。
解决方法:如果在项目中实体是使用逆向工程生成时,就需要注意,前台获取到的数据封装到json中的数据库表字段名与逆向工程生成的实体内的数据库表字段名的大小写保持一致,否则,前台传递的数据使用Map能接受到,但是如果与实体内的字段名的大小写不一致,就会接受不到数据,实体内数据全为空,插入数据时报错。
如果这些参数并不是同一个类的不同属性
form表单中增加了一项验证码:verifycode。此时,假如ajax提交的JSON数据为
假ajax提交的JSON数据为
1 |
|
但是verifycode并不是User类中的属性,不能由@RequestBody User user接收
就可以用1.@RequestBody String body
2.(@RequestBody Map<String,String> map
1 |
|
1 |
|
GET请求中,因为没有请求体,只有url的QueryString,所以@RequestBody并不适用。
•在GET请求中,不能使用@RequestBody。 •在POST请求,可以使用@RequestBody和@RequestParam,
day04
文件上传与下载
**Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码
我们只需要在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件,例如:
这里传上来的file一般是存在C盘的临时文件.tmp,请求结束后自动删除
临时文件(TMP文件),所以需要转存到指定位置,否则本次请求完成后临时文件删除
可以用file.transferTo(地址)转存到指定位置
//将临时文件存储到指定位置
file.transferTo(new File("D:\\hello.jpg"));
File类
概述:文件和目录(文件夹)路径名的抽象表示形式(类路径)
file类的构造函数只是创建一个File实例,并没有以文件做读取等操作,因此路径即使是错误的,也可以创建实例不报错
1
2
3
4
5
6
7
8//创建一个目录对象
basePath = "D:/test"
File dir = new File(basePath);
//判断目录是否存在
if (!dir.exists()){
//目录不存在需要创建
dir.mkdir();
}
输入流与输出流
输入流 FileinputStream(File file或者String filePath)
输出流FileoutputStream(File file或者String filePath)
每次执行read()方法,read每调用一次就会读取文本内容的下一个字节
read()返回-1时候代表读完
①read() :从输入流中一次读取一个字节,读完一个字节自动读取数据的下一个字节,返回*0*到*255*范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回*-1*。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
②read(byte[] b) :从输入流中读取一定数量的字节,并将其读取存储在缓冲区数组 b 中。
以整数形式返回实际读取的字节数。
在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;每次读取的字节数是缓冲区数组的最大储存字节数(new byte[2] 数组最多储存2个字节,那么read(byte)每一次只能读到2字节,并且数组是满的状态),下一次调用读取的字节存入这个数组会替代掉上一次数组的内容(返回的是读了多少个字节而读到的字节内容储存到了b缓冲区中)
③read(byte[] bytes,int off ,int len) 参数的byte照样是缓存区数组,off是读取字节的开始位置,len是每次读取的的字节数
那么这个和上面read(b)的区别就是他指定了每一次读出多少个字节,而不再用每一次读满一个缓存数组的形式,并且这一个可以指定读取字节开始的位置。返回的也是实际每次读取到的字节数而不是字节,字节都储存在缓存数组里。(比如,new bety[10], read(bety,0,9),那么每次读进数组的是9个字节,那么每次数据就会剩下一个字节项,那么下一次用read读,读到的第一个字节就会放在数组的最后一个位置,而剩下的8个字节替换掉上次的前8个字节,想想就复杂 )。
一般是
1 |
|
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
//file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件删除
log.info(file.toString());
try {
//将临时文件存储到指定位置
file.transferTo(new File("D:\\hello.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
- MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。
- MultipartFile后面的参数名必须为file,因为需要和前端页面的name保持一致,否则不会生效
UUID,不需要任何参数生成一个唯一数字
UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符。UUID具有以下涵义:
- 经由一定的算法机器生成
为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的复杂特性在保证了其唯一性的同时,意味着只能由计算机生成。
1 |
|
@Value
1.读取application.yml的配置属性
@Value(“${user.name}”)
private String name;
前端js分析
调用了getCategoryList()函数,其中{‘type’:1}是参数param,type值为1,代表是菜品类型
res代表函数返回值R,如果成功返回则将R.data赋给this.dishList(菜品分类列表),所以R.data应该是List
———-》后端方法public R<LIst
param={‘type’,1}
通过url’/category/list’发送get请求,附带参数
传统方式后端可以不加@RequestParam
public R<LIst
也可以使用自动封装的实体类
public R<LIst
这里的参数可以是category是原参数param的type封装成category再转过来
Content-Tpye
1 |
|
lambda的几个使用场景
lambda能替换匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("thread run");
}
}
Runnable r = () -> {
System.out.println("thread run");
};
哪里有list,哪里就有lambda
//遍历输出集合
List<Integer> list=Arrays.asList(1,2,3,4,5);
list.forEach(x->System.out.print(x));
//当然也可使用方法引用
list.forEach(System.out::print);
//取出所有大于1的元素,并形成新的集合
List<Integer> collect = list.stream().filter(x -> x > 1).collect(Collectors.toList());
//获取学生的所有年龄集合
List<Integer> ageList=Arrays.asList(new Student("tom",20),new Student("jack",22))
.stream().map(Student::getAge).collect(Collectors.toList());
js分析
if(valid)这里是进行校验是否要进行
把当前页面的数据封装为一个param
、
序列化和反序列化
json序列化:就是JavaBean对象转化为JSON格式的字符串。
反序列化:就是序列化的反方向,将字符串转化为JavaBean。
前端要json字符串,后端要javaBean对象(假设后端采用java语言)怎么办?此时就需要json的序列化和反序列化了。
从前端json反序列化给后端需要@ResponseBody接受
事务
1.在serviceImpl加入@Transactional
2.启动类加**@EnableTransactionManagement**