ToDo后端
1 有一个能跑的spring项目,带一个hello world的api
使用 spring initializr 来创建一个web项目;
在src/main/java/com/example/ToDolist中,打开ToDolistApplication.java,添加方法
|
|
运行
|
|
@GetMapping("/hello") 注解定义了一个HTTP GET请求的处理方法,该方法接受一个名为name的请求参数。
输入name参数可以通过打开浏览器,在URL后面加上?name=justt。
|
|
或使用curl命令发送GET请求
|
|
2 新建todo类(包含todo的内容),在内存里(变量)新建一个todo类的array,填一些内容;新建一个api返回这些todo
新建controller和model包,在controller包中新建ToDoController类,处理HTTP请求并返回响应;在model包中新建ToDolist类。
3 新建一个api创建todo
|
|
这段代码是Java Spring框架中的一个导入语句,用于导入Spring MVC框架中的注解。Spring MVC是一个基于Java的Web应用程序框架,用于简化Web应用程序的开发。这段代码导入了Spring MVC框架中的@RestController、@RequestMapping、@GetMapping、@PostMapping等注解,以便在后续的代码中使用这些注解来定义RESTful Web服务。
@RestController注解是一个组合注解,它包括了@Controller和@ResponseBody。@Controller注解用于标识一个类或方法是一个控制器,Spring会自动将这个类或方法映射到URL上。@ResponseBody注解用于将控制器方法的返回值作为HTTP响应正文的正文。
@RequestMapping注解用于定义一个控制器方法处理HTTP请求。它接受一个字符串参数,表示请求的URL模式。当HTTP请求的URL与这个模式匹配时,Spring会自动调用这个方法。@GetMapping和@PostMapping注解是@RequestMapping的子注解,分别用于处理GET和POST请求。
|
|
这段代码是Java语言中导入的一个类库,名为java.util.concurrent.atomic。这个库提供了原子性操作的类,如AtomicLong。
AtomicLong是一个实现了Atomic类的Long类。这个类提供了原子性的long值操作方法,如getAndSet()、compareAndSet()、incrementAndGet()等。这些方法在多线程环境下能够保证原子性操作。
例如,使用AtomicLong可以保证线程安全的long值自增操作如下:
|
|
在上面的代码中,incrementAndGet()方法会原子性地递增counter的值,并返回新的值。这种原子性操作在多线程环境下非常有用,因为它可以避免并发问题,如数据竞争。
报错:Cannot invoke "java.util.concurrent.atomic.AtomicLong.incrementAndGet()" because "this.counter" is null
counter没有正确初始化,少了counter = new AtomicLong();
4 删除todo(怎么确定删哪一个?)
用请求中输入的id来找todos列表中是否有对应的id
|
|
-
为什么要这么设计URL(在id前后加“{}”)?
花括号
{}是语法的一部分,用来表示 URL 路径中的变量。这种用法允许你定义 RESTful API 的路径参数,并在控制器方法参数中使用这些变量。例如当发送一个 DELETE 请求到
1http://localhost:8080/api/todos/1时:
- Spring 看到这个 URL 匹配
@DeleteMapping("/{id}")。 - Spring 提取 URL 中的
1并将其转换为Long类型,然后赋值给deleteTodo方法的id参数。 - 方法内部会使用这个
id执行删除操作。
- Spring 看到这个 URL 匹配
HTTP方法和含义
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。
- PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)。
- DELETE(DELETE):从服务器删除资源。
RESTful是面向资源的,每种资源可能由一个或多个URI对应,但一个URI只指向一种资源。
URL设计规范
URL为统一资源定位器 ,接口属于服务端资源,首先要通过URL这个定位到资源才能去访问,而通常一个完整的URL组成由以下几个部分构成:
1URI = scheme "://" host ":" port "/" path [ "?" query ][ "#" fragment ]scheme: 指底层用的协议,如http、https、ftp host: 服务器的IP地址或者域名 port: 端口,http默认为80端口 path: 访问资源的路径,就是各种web 框架中定义的route路由 query: 查询字符串,为发送给服务器的参数,在这里更多发送数据分页、排序等参数。 fragment: 锚点,定位到页面的资源
优点:将动作放到URL的Path上清晰可见,更利于团队的理解和交流
缺点:操作方式繁琐;实际业务API可能有各种需求比较复杂,单单使用资源的增删改查可能并不能有效满足使用需求,强行使用RESTful风格API只会增加开发难度和成本。
5 新建一个api修改todo(怎么确定改哪一个?)
-
Boolean和boolean
在 Java 中,基本类型(例如
boolean、int、char等)不能与null进行比较,因为基本类型不能为null。只有对象(引用类型)才能为null。在你的例子中,
completed字段是Boolean类型的包装类对象,而不是基本类型boolean,所以可以与null进行比较。不过,如果你在某些地方使用了基本类型
boolean而导致这个错误,需要改成使用包装类型Boolean。
通过id确定修改哪一个ToDo,使用PATCH,用户提供需要修改的内容或者完成情况。
为什么要用到ResponseEntity,比较它和直接返回ToDolist
前端
(index):111 Error deleting todo: SyntaxError: Unexpected token ‘D’, “Deleted” is not valid JSON
连接数据库 MySQL Spring Data JPA
docker 创建数据库
|
|
|
|
|
|
查看所有容器(包括停止的)的状态。
- 在pom.xml文件中添加依赖
|
|
报错mysql:mysql-connector-java:jar:unknown was not found in https://repo.maven.apache.org/maven2 during a previous attempt.
修改为
|
|
-
创建数据库
docker run --name=mysql-server -p=3306:3306 -e=MYSQL_ROOT_PASSWORD=securepswd -e=MYSQL_DATABASE=todolistdb -d mysql:8.4
遇到的问题
|
|
https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/GenerationType.html
URL规范化(RESTful)
HTTP状态码规范化、错误返回规范化(RESTful)
-
遇到的问题
改写deleteToDo时,
HttpStatus.NO_CONTENT通常用于表示服务器成功执行了请求,但没有返回任何内容。所以想使用ResponseEntity并且不希望返回任何内容(也就是没有响应体),使用了Void作为泛型参数。.build()方法创建了一个没有主体内容的ResponseEntity实例。
|
|
- git仓库管理
- git checkout main
- git checkout -b 新分支名
- 编写代码
- commit
- git push –set-upstream origin 新分支名
- merge
- git checkout main
- git pull
XXXException :继承原生的 Exception ,本项目中主要用于传递 messsage
XXXAdvice: 处理这个特定异常,在本项目中返回特定格式的 Response
分页查询
-
遇到的问题
-
import
Pageable类型错误org.springframework.data.domain.Pageable和java.awt.print.Pageable是两个完全不同的接口,它们服务于不同的目的,这就是为什么在Spring Data JPA环境中应该使用org.springframework.data.domain.Pageable而不是java.awt.print.Pageable。 以下是一些关键点,解释了为什么应该使用org.springframework.data.domain.Pageable:- 目的不同:
org.springframework.data.domain.Pageable是Spring Data库的一部分,专门用于分页和排序操作。它定义了分页请求的抽象,比如页码、页面大小和排序方向。java.awt.print.Pageable是Java AWT (Abstract Window Toolkit)的一部分,用于定义能够分页打印文档的类。它用于打印任务,与数据库查询分页无关。
- 使用场景不同:
- 当你使用Spring Data JPA进行数据持久化时,
org.springframework.data.domain.Pageable用于在数据库查询中实现分页。例如,在REST API中返回分页的列表数据。 java.awt.print.Pageable则用于图形用户界面(GUI)应用程序中,涉及到将内容分页打印到纸张上。
- 当你使用Spring Data JPA进行数据持久化时,
- 功能不同:
org.springframework.data.domain.Pageable提供了方法来获取分页信息,如当前页码、页面大小、排序等,这些都是执行分页查询所必需的。java.awt.print.Pageable提供了方法来获取关于打印文档分页的信息,如每页的内容范围。
- 集成和兼容性:
org.springframework.data.domain.Pageable与Spring Data JPA无缝集成,允许你轻松地在Spring环境中使用分页功能。java.awt.print.Pageable与Spring Data JPA不兼容,因为它不是为了数据库操作设计的。 简而言之,org.springframework.data.domain.Pageable是为了与Spring Data JPA一起使用而设计的,而java.awt.print.Pageable是为了与打印相关的任务一起使用而设计的。因此,在你的Spring Data JPA项目中,你应该使用org.springframework.data.domain.Pageable来实现分页查询。
- 目的不同:
-
用户
创建流程
- 创建用户模型。 User.java
- 创建用户仓库接口。 UserRepository.java
- 创建用户控制器UserController.java来处理注册和登录请求。
- 更新ToDolist.java模型,使其与用户关联。
密码加密
调用Spring Security中的BCryptPasswordEncoder类进行加密。
但是Spring Security默认配置要求所有请求都必须进行认证,因此进入了其基本的登录界面。
我使用的Spring Boot版本为3.3.1,WebSecurityConfigurerAdapter已被标记为过时,因此使用SecurityFilterChain。由于还没有实现鉴权,配置中打开了所有的权限。
|
|
对于BCryptPasswordEncoder,同一个明文加密两次,加密结果是不同的。因此使用BCryptPasswordEncoder去加密登录密码,在登录验证时,要使用BCryptPasswordEncoder的matches方法来进行验证。参考:https://cloud.tencent.com/developer/article/1779217
|
|
JWT实现(参考https://springdoc.cn/spring-boot-spring-security-jwt-mysql/)
JwtAuthenticationEntryPoint
遇到报错Class 'JwtAuthenticationEntryPoint' must either be declared abstract or implement abstract method 'commence(HttpServletRequest, HttpServletResponse, AuthenticationException)' in 'AuthenticationEntryPoint',发现是没有自动导入AuthenticationException包。 (为什么?)
AuthenticationEntryPoint是一个入口点,用于检查用户是否已经通过身份认证。在 JWT 中使用 Spring Security 时,就必须对其进行继承,以提供更好的 Spring Security 过滤器链(filter chain)管理。