续
上一篇我们进行了立项,并撰写了数据库代码。
今天就让我们来继续接下来的项目式学习。
不过在正式开始前我很好奇这两个命令有什么用,分别是flyway和hibernate。
原来是数据库创建和迁移的应用。
因为我们本次学习的重点不在于性能和优化,而是在于跑通一个Java Web项目的MVP,因此此处从简,我们选择Hibernate。
按照路径,经过环境部署和数据库代码后,应当开始写API的代码了。
通过回顾我们可知目前有如下的API代码:
用户注册
我们第一个需要实现的是用户注册的API代码。
Repository 接口
完整的我就不展示了,我仅展示我有疑惑的地方:
这段代码其实解释的很清晰,但是我还是有一个问题:对于自定义查询的方法的方法名,是否有要求和规范呢?
答案是当然的:
不过为了保证准确我还是去查一下Spring Data JPA的官方文档比较合适。
会发现有错误的地方:NotEquals
关键字并不存在。除此之外也是不全的,不过不全这一点不需要责怪AI倒是,需要全面的话还是需要去看对应的文档。
然后第二个点:TaskRepository
中的Pageable
类型是什么?以及为什么TaskRepository
没有使用Repository
这个注解?
-
Pageable
类型,我觉得解释的是很清楚的:
-
TaskRepository
为什么没有使用Repository
这个注解,也是很清楚的:
对于TaskRepository
为什么没有使用Repository
这个注解的原因提醒了我,那UserRepository
是否也可以不使用Repository
这个注解呢?
答案也是肯定的,不过为了项目的维护性最好还是写上(强调类型!不要学Python那样都允许你不直接声明类型!)
所以在代码里对于TaskRepository
我依旧是加上Repository
这个注解的。
Service
Service中我的疑问不多,基本上就只有一个:
为什么要使用interface+impl组合的方式而不是使用class呢?
啰啰嗦嗦的...不过也是我学的少了,之前都了解面向过程和面向对象,现在学了一个新的设计模式:面向接口。
说白了就是把一个class拆成interface+impl来解耦合呗。
Security
我其实并不清楚为什么需要SecurityConfig
这个配置类,所以去问了一下,发现有三点作用:
- 禁用CSRF保护: 因为我们是使用的token来进行验证,遭到CSRF的概率会降低,所以可以关闭掉。
-
sessionManagement
的管理策略设置为STATELESS
:和我们第一个作用是相关联的,使用了无状态来使用token进行验证用户身份。 - 密码编码器Bean:经过多轮对话可知
PasswordEncoder
这个接口在SpringBoot中考虑到安全问题并没有使用Bean
注解来自动注入,而是需要开发人员来手动进行注入。同理,其他安全组件也是需要手动设置其Bean
的。
代码更优实现
好了,问了自己想问的问题后又到了我们的一个常规环节:某一部分代码是否有更优实现?
我们在尝试找到更优实现的时候需要注意的一个点是如果这部分代码本身很短,其实就没必要找更优实现了——没有优化的余地。
就像你一个打印语句就是打印语句不需要去找更优实现那样,你针对一个打印语句进行提问来尝试找到优化只会引入额外的不必要复杂度,不过作为扩展倒是可以尝试一下。
-
Repository 接口
可优化的地方还挺多,不过目前来来说都没必要。
-
DTO
对于DTO则主要是对于数据的校验这一块了,但是数据校验的话我还是想就在前端进行实现,减少后端的计算压力。
-
Service层
目前基本上也是大部分都用不上。
总的来说就是都有用但是目前都用不上,因此不对原代码进行修改。
用户登录
在用户注册的API的基础上进一步,进行用户登录的API开发就会容易很多了——倒不如说接下来的API开发都会容易一些。
-
DTO
-
Service 层
在Service这里AI写了一个极其不安全的代码:
细心的朋友可能就看出来了:明文token。
一般来说我们的token都要经过签名才会发送回客户端,这里我也指出了AI的问题,不过得到的回答是因为当前是在学习的环境所以用简单的示例代码...
好吧,算你圆过去了。
-
最后是Controller 层
任务创建
完成了用户注册和登录的API后就需要来完成任务相关的API了。
-
DTO
-
Service 层
这里同样需要注意的一个点是用户在这里使用的是硬编码而非从数据库中拉取对象:
-
最后是Controller 层:
最后测试响应是否符合预期:
任务查询
-
DTO
按照习惯,因为查询一般使用的是
GET
请求,故一般是在URL的请求参数中来传入分页信息的,故不需要DTO,这点常识AI还是有的:
-
Service 层
这里我们同样也是暂时使用硬编码作为占位符。
-
Controller 层
一切顺利——假如我没有执行的话...
是的,很明显的递归BUG。
丢给AI进行处理看看?
遇到陌生领域的BUG怎么办?直接按照AI说的去做吗?
不,我会先进行多个AI的交叉验证。
-
Grok:
-
Deepseek:
-
Gemini:
当这个解决方案被多方均判断为有效且正确的情况下才会被采取。
接下来就让我们把这个方案反映到我们的代码中,然后再进行测试:
正常响应。
任务搜索
接下来就是进行我们的任务搜索的API实现了。
首先,同样的,对于我们的任务搜索也不需要专门写一个DTO。
-
Service 层
-
Repository 层
-
Controller 层
最后正常响应:
任务更新
-
DTO
-
Service 层
-
Controller 层
最后进行测试,响应符合预期:
任务删除
貌似我前面录入了太多无用的代码,接下来的就删掉一些吧:
-
Service 层
-
Controller 层
运行,报错:
外文看不懂啦!
丢给AI看看:
同样的,进行交叉验证:
-
Grok:
-
Deepseek:
-
Gemini:
总的来说,对,但不完整。
不过对当前来说的话确实是只要删掉对应的代码就可以完成了。
运行,响应符合预期:
-
正常删除:
-
未找到该任务:
终
至此,后端的API便开发完成了,接下来要做的就是进行前端开发。