SpringBoot个人学习笔记

SpringBoot

1注解常用知识点

@slj4

加在applicaiton()

就可以使用log.info()用于日志

@Resource

按名字注入

@Autowired

按类型注入

@RequestBody

1
public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee)

接受前端页面传递过来的数据,根据同名字

而Body请求体只存在于POST请求

MD5加密

1
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));

@Bean

@Bean是放在方法的注释上了,因为它很明确地告诉被注释的方法,你给我产生一个Bean,然后交给Spring容器,剩下的你就别管了

记住,@Bean就放在方法上,就是让方法去产生一个Bean,然后交给Spring容器。

1
2
3
4
5
6
class A{
@Bean
public AccountDao accountDao(){
return new AccountDao();
}
}

不知道大家有没有想过,用于注册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
2
3
4
5
假如IOC容器就是一间空屋子,首先这间空屋子啥都没有,我们要吃大餐,我们就要从外部搬运食材和餐具进来。这里把某一样食材或者某一样餐具搬进空屋子的操作就相当于每个注册Bean的注解作用类似。注册Bean的注解作用就是往IOC容器中放(注册)东西!
用于注册Bean的注解: 比如@Component , @Repository , @ Controller , @Service , @Configration这些注解就是用于注册Bean,放进IOC容器中,一来交给spring管理方便解耦,二来还可以进行二次使用,啥是二次使用呢?这里的二次使用可以理解为:在你开始从外部搬运食材和餐具进空屋子的时候,一次性搬运了猪肉、羊肉、铁勺、筷子四样东西,这个时候你要开始吃大餐,首先你吃东西的时候肯定要用筷子或者铁勺,别说你手抓,只要你需要,你就会去找,这个时候发现你已经把筷子或者铁勺放进了屋子,你就不用再去外部拿筷子进屋子了,意思就是IOC容器中已经存在,就可以只要拿去用,而不必再去注册!而拿屋子里已有的东西的操作就是下面要讲的用于使用Bean的注解!
————————————————
版权声明:本文为CSDN博主「宜春」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44543508/article/details/103718958

一类注解是用于使用Bean

1
用于使用Bean的注解:比如@Autowired , @Resource注解,这些注解就是把屋子里的东西自己拿来用,如果你要拿,前提一定是屋子(IOC)里有的,不然就会报错

接口方法接收前端传入参数

传统方式—针对localhost:8080/shop?page=1

*如果是通过这种传送数据参数给后端

image-20230424234625955

用的是@RequestParam

如果省略了也是默认@RequestParam,所以则可以直接(int page,int pageSize)即可

接口方法参数不使用任何注释:这其实也是默认使用的是Request.getParameter() 方法对参数进行获取的,只是没有显示使用@RequestParam而已,

1
2
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name)

也可以用@RequestParam

RESTFUL格式—-针对localhost:8080/10048

这样的加个@GetMapping(“/{id}”) @PathVariable也行

image-20230424234642164

JSON方式—-针对POST方法的请求体

​ 加@RequestBody

只有管理员(admin)才能看到启用,禁用按钮?非管理员看不见该按钮

下面是代码展示< v-if><>

可以利用v-if完成要求

出现

image-20230424234710060

从userInfo中取出username,并赋值给user模型数据
在这里插入图片描述
判断模型数据user的值是否等于admin,若等于则显示按钮
在这里插入图片描述

当maven无法下载源代码时候执行

【检查方式maven正确情况下,再执行本步骤】则在项目下,项目根目录下 或 pom.xml同级目录中执行

mvn dependency:resolve -Dclassifier=sources

可能原因2:网络问题

1.没换源且没魔法上网

2.换了源又魔法上网

2.servlet,session,request,application

  1. request

request是表示一个请求,只要发出一个请求就会创建一个request,它的作用域:仅在当前请求中有效。

用处:常用于服务器间同一请求不同页面之间的参数传递,常应用于表单的控件值传递。

方法:request.setAttribute(); request.getAttribute(); request.removeAttribute(); request.getParameter().

  1. session

服务器会为每个会话创建一个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)

  1. Application(ServletContext)

作用范围:所有的用户都可以取得此信息,此信息在整个服务器上被保留。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
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password:
# 开启mp的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

BaseMapper<>

1
2
3
4
@Mapper
public interface StudentMapper extends BaseMapper<Student> {

}

4.不用再写sql语句不用再写mapper,已经完成

通用service的IService

1
2
3
4
5
public interface StudentService extends IService<Student>{
}

当子类不写泛型然后父类写了
这个StudentService继承的 extends IService<Student>,其实子类StudentSercice就默认继承了Student为泛型

通用Impl的ServiceImpl

public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}

java驼峰命名法,映射,数据库下划线命名法

1
2
3
4
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true

过滤器Filter

1.编写Filter

@WebFilter(filterName = “” , urlPatterns = “/*”)//对所有的都先加入过滤器,后面再针对不同类选择是否直接放行

@slf4j

public class LoginCheckFilter implementes Filter{}

image-20220821153738660

2.启动类加入写@ServletCOmponentScan

image-20220821153721415

@ServletComponentScan

在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码

filterChain,doFilter(request,response)放行,进行下一个流程

1
filterChain.doFilter(request,response);

新增员工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

image-20220821164355766

service利用了mapper使用数据库

全局异常处理器GlobalExcptionHandler

我们的程序进行异常捕获,通常有两种处理方式:

  1. 在Controller方法中加入try、catch进行异常捕获
  2. 使用异常处理器进行全局异常捕获(推荐使用第二种方式)

在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
3
4
5
6
7
8
9
10
11
12
13
/**
* 配置MP的分页插件
*/
@Configuration
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

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 queryWrapper = new LambdaQueryWrapper<>();

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
2
3
4
5
6
7
8
public R<Page> page(int page, int pageSize)
{
Page<Category> pageInfo = new Page<>(page,pageSize);
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByAsc(Category::getSort);
categoryService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}

RESTFUL风格

在这里插入图片描述

@GetMapping,处理get请求
@PostMapping,处理post请求
@PutMapping,处理put请求
@DeleteMapping,处理delete请求

4.过滤器Filter

image-20220721114134952

生命周期:伴随web启动而init,web停止而destory

filterchain.doFilter()将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源

// 让程序继续往下访问用户的目标资源

1
filterChain.doFilter(request,response);

匹配URL路径

1
2
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
1
2
3
4
5
6
7
8
9
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match){
return true;
}
}
return false;
}

5.拦截器Inteceptor在这里插入图片描述

2.在config注册

image-20220721114715164

@ResponseBody与response.getWriter().write()

@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象,通常我们使用用来返回JSON数据或者是XML数据

image-20220721152750356

前端页面:我这里使用的是ajax提交,指定dataType为json,接收到后台传来的数据会转为json对象

image-20220721152815317

**对于response.getWriter().write(JSSONObject.toJSON())**的效果

效果也差不多

image-20220721152842917

在这里插入图片描述

@RestController

@Controller和@ResponseBody(加在方法/类上面)一起使用 == @RestController的作用相同。

在mysql就可以设置属性为不可重复性Unique

image-20220721153358149

如果存入重复数据username则会报错

image-20220721154900047

image-20220721154813777

F12查看network

可以看见发送到URL请求

image-20220721153712338

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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;


//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;


//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;


//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

2编写类MyMetaObjectHandler implements MetaObjectHanlder

记得加入@Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入元对象字段填充(用于插入时对公共字段的填充)
*
* @param metaObject 元对象
*/
@Override
public void insertFill(MetaObject metaObject) {
metaObject.setValue("createTime" , LocalDateTime.now());
metaObject.setValue("updateTime" , LocalDateTime.now());
metaObject.setValue("createUser" , BaseContext.getCurrentId());
metaObject.setValue("updateUser" , BaseContext.getCurrentId());

}

/**
* 更新元对象字段填充(用于更新时对公共字段的填充)
*
* @param metaObject 元对象
*/
@Override
public void updateFill(MetaObject metaObject) {
metaObject.setValue("updateUser" , BaseContext.getCurrentId());
metaObject.setValue("updateTime" , LocalDateTime.now());
}

1.对象映射器

JacksonObjectMapper作用就是在后端controller返回response给前端网页时候,将java对象转为json对象传回

1
2
3
4
5
\* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象

\*JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]

\* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]

2.在config替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}

提示报错:java: 找不到符号

解决方式clean和package

image-20220729190910388

元数据(Metadata)

典型的元数据(Metadata)元素:

  • 标题和描述
  • 标签和分类
  • 谁生成的,何时生成的
  • 最后一次是被谁更改的,何时更改的
  • 谁能访问或者更新

关于客户端的http请求与线程

同一个http请求是同一个线程

比如我点击保存,发送请求,会有三个流程loginCheckFilter过滤器,EmployeeCOntroller,MyMetaObjectHandler

image-20220729194016614

image-20220729194603645

ThreadLocal就是在一个线程中用于保存的局部变量

image-20220729194412201

image-20220821145945528

前置知识

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;
}

前端

image-20220822145137197

@RequestMapping

是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。

image-20220822150235770

image-20220822150250562

@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
2
获取到的id为:2
获取到的name为:zhangsan

image-20220822150624194

1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/user/{id}")

public string test(@PathVariable Integer id)

{\

​ ...

System.out.println(id);

}
1
2
获取到的id为:2
获取到的name为:zhangsan

@RequestParam

实例:

1
http://localhost:8080/user?id=1
1
2
3
4
5
@GetMapping("/user")
public String testRequestParam(@RequestParam Integer id) {
System.out.println("获取到的id为:" + id);
return "success";
}

注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。

请求体只有一个,@RequestBody最多只能有一个请求体

而@RequestParam()可以有多个。

@RequestBody –> JSON字符串部分

@RequestParam –> 请求参数部分

application/json格局图
img

form-data、x-www-form-urlencoded格局图

img

@RequestBody

get请求没有请求体不能用requestbody

自定义参数封装过程原理【用实体类接收参数】

@RequestBody,get请求的url参数传入等可以接收前端传来的多个参数,然后Controller方法中会使得其自动封装为一个实体类

在使用ajax发送请求时,如果发送的JSON数据是一个类中的不同属性,在Controller方法中使用@RequestBody会直接封装进该类中

实例:

传来同一个类的多个参数

User

1
2
3
4
5
1 public class User implements Serializable {
2 private Integer user_name; //用户名
3 private String user_password; //用户密码
4 ......
5 }

前端传来————此时ajax提交的JSON数据为

1
1 data:JSON.stringify({"user_name":admin,"user_password":123)

后端接受—————-就可以直接@RequestBody

1
public Boolean Login(@RequestBody User user)

问题:SpringBoot框架下,控制层代码接受前台传递的参数,使用注解@RequestBody接受时,用实体作为接受参数,实体接受不到参数。新增时,报sql空数据异常。

解决方法:如果在项目中实体是使用逆向工程生成时,就需要注意,前台获取到的数据封装到json中的数据库表字段名与逆向工程生成的实体内的数据库表字段名的大小写保持一致,否则,前台传递的数据使用Map能接受到,但是如果与实体内的字段名的大小写不一致,就会接受不到数据,实体内数据全为空,插入数据时报错。

如果这些参数并不是同一个类的不同属性

form表单中增加了一项验证码:verifycode。此时,假如ajax提交的JSON数据为

假ajax提交的JSON数据为

1
1 data:JSON.stringify({"user_name":admin,"user_password":123,"verifycode":666})

但是verifycode并不是User类中的属性,不能由@RequestBody User user接收

就可以用1.@RequestBody String body

​ 2.(@RequestBody Map<String,String> map

1
2
3
4
5
6
1 @RequestMapping(value = "www.tengyao3zc.cn/Login",method = {RequestMethod.POST})
2 public @ResponseBody Boolean Login(@RequestBody String body) {
3 //此时body是整个请求体的内容
4 System.out.println(body);
5 //······
6 }
1
2
3
4
5
6
7
8
1 @RequestMapping(value = "/Login",method = {RequestMethod.POST})
2 public @ResponseBody Boolean Login(@RequestBody Map<String,String> map) {
3 //此时map.get("user_name"www.jintianxuesha.com)就是前端的user_name
4 System.out.println(map.get("user_name"));
5 //map.get("user_password" www.yuntianyul.com)就是前端的user_password
6 System.out.println(map.get( www.jinliyld.cn"user_password"));
7 //map.get("www.javachenglei.com verifycode")就是前端的verifycode
8 System.out.println(map.get("verifycode"));

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类

  1. 概述:文件和目录(文件夹)路径名的抽象表示形式(类路径)

  2. 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /**

\* 文件下载

\* @param name

\* @param response

*/

@GetMapping("/download")

public void download(String name, HttpServletResponse response){



try {
//输入流,通过输入流读取文件内容
​ FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));
//输出流,通过输出流将文件写回浏览器
​ ServletOutputStream outputStream = response.getOutputStream();
​ response.setContentType("image/jpeg");
int len = 0;
​ byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1){
​ outputStream.write(bytes,0,len);
​ outputStream.flush();
​ }
​ outputStream.close();
​ fileInputStream.close();
​ } catch (Exception e) {
​ e.printStackTrace();
​ }

}
@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
2
3
    //使用UUID重新生成文件名,防止文件名称重复造成文件覆盖

​ String fileName = UUID.randomUUID().toString() + suffix;//dfsdfdfd.jpg

@Value

1.读取application.yml的配置属性

@Value(“${user.name}”)

private String name;

image-20220823160603571

前端js分析

image-20220823100440835

调用了getCategoryList()函数,其中{‘type’:1}是参数param,type值为1,代表是菜品类型

res代表函数返回值R,如果成功返回则将R.data赋给this.dishList(菜品分类列表),所以R.data应该是List

———-》后端方法public R<LIst> list()

image-20220823100746047

param={‘type’,1}

通过url’/category/list’发送get请求,附带参数

image-20220823112333702

image-20220823112345186

传统方式后端可以不加@RequestParam

public R<LIst> list(Mapping type)

也可以使用自动封装的实体类

public R<LIst> list(Category category)

这里的参数可以是category是原参数param的type封装成category再转过来

Content-Tpye

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
text/html  :HTML格式
text/plain :纯文本格式
text/xml :XML格式

image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png :png图片格式

application/xml : XML数据格式
application/json : JSON数据格式
application/pdf : pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如文件下载)

application/x-www-form-urlencoded :

<form encType="">中默认的encType,
form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)。
服务器收到的raw body会是,name=aaa&key=bbb。


multipart/form-data : 表单上传文件

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分析

image-20220825143810519

if(valid)这里是进行校验是否要进行

image-20220825143910403

把当前页面的数据封装为一个param

序列化和反序列化

json序列化:就是JavaBean对象转化为JSON格式的字符串。

反序列化:就是序列化的反方向,将字符串转化为JavaBean。

前端要json字符串,后端要javaBean对象(假设后端采用java语言)怎么办?此时就需要json的序列化和反序列化了。

从前端json反序列化给后端需要@ResponseBody接受

事务

1.在serviceImpl加入@Transactional

2.启动类加**@EnableTransactionManagement**


SpringBoot个人学习笔记
http://yoursite.com/2023/04/21/SpringBoot/
作者
Fars
发布于
2023年4月21日
许可协议