1.需求分析
需求规格说明书,产品原型
2.设计
UI设计,数据库设计,接口设计
3.编码
项目代码,单元测试
4.测试
测试用例,测试报告
5.上线运维
软件环境安装,配置
1.开发环境develpoment:开发人员在开发阶段使用的环境,外部用户无法访问
2.测试环境testing:测试服务器,部署到并给测试人员测试
3.生产环境production:线上环境,正式提供对外服务的环境
定位:为餐饮企业定制的软件产品,管理端和用户端
项目架构:(体现项目中的业务功能模块)
用于展示项目的业务功能,一般由产品经理进行设计,一般是html页面
展示项目中使用到的技术框架和中间件
前端工程基于nginx实现,启动nginx服务可以访问,默认80端口。
后端工程基于maven进行项目构建,分模块开发.
通过IDEA的VCS创建本地仓库,共享到github。
通过Navicat运行sql语句,创建数据库,表结构。
第一个遇到的问题就是默认sql数据库密码和自己的数据库密码不一样,在配置文件中更改,解决。
通过在controller的login方法处打断点进行单步执行,来debug观察流程,了解异常类的定义和捕获.
生成JWT令牌(不懂,去学)
利用builder来构建传回前端页面的返回数据VO
直接给了后端工程,要去了解一下登录功能从0到1的过程
将前端发送的动态请求由nginx转发到后端服务器
HTTP和反向代理web服务器
好处和优点:
1提高访问速度
2进行负载均衡(把大量的请求按照我们制定的方式均衡分配给集群中的每台服务器)
3保证后端服务的安全
负载均衡基于反向代理实现,都是proxy_pass
员工表密码明文存储,安全性低.
用md5加密后存储,明文加密MD5只能加密,是单向的。
// TODO可以标记遗留标签页,可以方便后期查看
//md5传入的是byte数组 password = DigestUtils.md5DigestAsHex(password.getBytes());
数据库改成md5加密后字符串,serviceimpl中使用工具md5加密
用Yapi进行接口文档导入,Yapi pro接口管理平台。
导入json类型的接口文件。
使用swagger需要按照它的规范去定义接口以及接口相关信息,就可以租到生成接口文档,以及在线接口调试页面。
Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。
1.导入knife4j的maven坐标
2.在配置类中加入knife4j相关配置
3.设置静态资源映射,否则接口文档页面无法访问
Yapi和Swagger: 1Yapi是设计阶段使用的工具,管理和维护接口
2.Swagger是后端开发阶段使用的框架,帮助开发人员做接口测试
通过注解可以控制生成的接口文档,使接口文档具有更好的可读性,常用注解如下:
账户的唯一性,手机号为合法的11位手机号码,身份证号校验18位,密码默认为123456
tips:当前端提交的数据和实体类中对应的属性差别较大时,建议使用DTO来封装数据
1.通过DTO封装数据(Controller层)
2.在Controller层中传给employeeService.
3.在Service的实现ServiceImpl中采用属性拷贝,并且把没有涉及到的属性封装
4.在ServiceImpl中调用Mapper执行Insert语句
5.返回Result对象
1.通过接口文档测试(常用)
jwt令牌校验(传过来的token与服务器token进行比较)
在swagger中登录获取jwt令牌token,设置swagger全局变量进行测试
2.通过前后端联调测试(需要前端功能编写完毕)
1.录入用户名存在,抛出异常未处理
全局异常处理器捕获sql相关异常,添加捕获,判断异常信息里是否包含关键语句,返回Result结果并提示msg错误信息。
2.新增员工时创建人修改人id设置为了固定值
jwt的大致流程:
动态方式获取id,在拦截器取得token中保存的id.
ThreadLocal并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
注:每个线程中执行一系列的代码操作.
可以将ThreadLocal的值设置为当前用户的id,在请求发到服务端时候设置,在新增用户设置创建人修改人时候get取到,实现动态获取。
前端提交的数据,后端发送给前端的结果数据
不是json格式而是Query地址栏问号的形式传参
这一步骤主要是熟练接口
1.根据前端传来的数据设计DTO
2.统一封装成PageResult对象再用Result的泛型设置为PageResult返回给前端
(注解问题GetMapping和PostMapping值的是访问url,RequestMapping是最大的一级)
3.代码编写,从Controller到Service到ServiceImpl到Mapper
4.这里是动态sql,需要编写xml文件
5.借助PageHelper来简化分页(底层基于ThreadLocal来实现的,存入变量page,在sql语句中插入,来实现limit)
问题描述:准备测试打开doc.html,也就是knife4j框架的文档页面,发现接口全部消失。
解决:通过排查knife4j配置文件以及项目结构发现是因为不知道什么时候把controller包放进来handler包,导致扫描不到接口。(我真蠢QAQ)
文档接口测试要注意token的有效期,在application配置的。
前后端联调测试发现创建时间不符合阅读习惯,计划修改。
时间问题
1.属性上加注解,对日期进行格式化(只能进行单个属性的格式化)
2.在WebMvcConfiguration中扩展Spring MVC的消息转化器,统一对日期类型进行格式化处理。 (可以统一处理,进行一系列格式转换)
一系列的操作》消息转换器》对象转换器(直接给出)
可以对状态为启动的进行禁用操作
可以对状态为禁用的员工账号进行启用操作
状态为禁用的员工账号不能登录系统
还是熟悉接口,能够知道应该用什么接受,传出什么,用什么注解
注意:如果是查询类,需要返回数据,所以要加上泛型,但是非查询类可以不用加泛型
路径参数要加上注解@PathVariable
json格式要加上@RequestBody
常规业务代码开发感悟:
1.在Controller中新建对应方法,写入对应参数,注意参数的注解{例如上面},和整个方法的注解(PostMapping?GetMapping?ApiOpreation?)
2.首先在Controller拿到前端传来的数据,一般都用单独对应的DTO进行封装(好像是MVC框架的功能特性)
3.根据功能进行数据的返回,用的是统一的Result封装结果
4.调用Service的方法(在Service接口中新建)
5.对应的在ServiceImpl中实现接口
6.在实现中执行具体的逻辑代码操作,不同的要求有不同的逻辑,目的是实现功能,通常要调用对应的Mapping操作数据层(sql数据库)
7.在对应的Mapping中新建方法并实现sql语句(其中根据功能的要求有多种实现方法,包括但不限于a直接用@Insert()注解写简单的sql,b在对应的mapping.xml中写sql语句,c有的功能还需要借助例如PageHelper等工具来实现动态sql的编写,d直接用
8.记得完善注释,没实现的地方要加//TODO标记,get请求要注意返回的类型(很重要)
两种测试方法均无误
根据id查询员工,用于点修改按钮后在新页面回显信息
编辑员工信息修改类是put的请求方式
根据接口进行代码开发
常规开发,注意要分两步走,先是数据回显,然后是数据修改,要点已经总结。
问题:编辑员工功能测试返回500报错
数据库异常。
解决:经过排查后发现是Mapper中的的update里的sql语句update_User忘记加_了,导致程序找不到这个属性。
已解决
分类的名称唯一
分类需要按照类型分:菜品分类和套餐分类
新添加的分类默认为禁用状态
接口设计分析,数据库设计分析
从底向上导入,可以不报错,compile一下防止不自动编译
测试不解的地方:为什么删除分类时候要考虑是否关联菜品?
业务表中的公共字段
JAVA代码存在冗余,不便于维护
通过切面AOP来统一拦截
1.自定义注解AutoFill,用于标识需要进行公共字段填充的方法
2.自定义切面类AutoFillAspect,拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
技术点:枚举,注解,AOP,反射
@Target注解自JDK1.5之后就有了,其作用是定义在注解的上方,表明其注解的作用范围。
@Retention修饰注解,用来表示注解的生命周期。
@Aspect 就是把一个类定义为切面供容器读取。
@@Component:定义Spring管理Bean(也就是将标注@Component注解的类交由spring管理)
@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写下面这段代码,并且想用log,就必须写代码:
private final Logger logger = LoggerFactory.getLogger(当前类名.class);
切入点,即能通过@PointCut中的模式字符串匹配到的方法。
//拦截Mapper包下所有的类* 所以的方法* 匹配所有参数类型(..),并且只对加了AutoFill注解的方法起作用 @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
AOP中有关键步骤有三个:切面,切入点,通知(代码增强部分,有很多类型)
1.获取到当前拦截的方法在数据库上操作的类型
2.获取到操作的对应实体对象(参数)
3.准备赋值的数据(时间和当前登录用户的id)
4.根据不同的操作类型,对实体对象进行赋值
测试无误,但是要加强java基础的学习,不懂的地方主要是反射,注解这一类的问题和对应的处理过程,抽空去复习吧.....
要求:
菜品名称必须唯一
菜品必须属于分类下,不能单独存在
新增菜品时可以根据情况选择菜品的口味
菜品必须对应一张图片
接口设计:
根据类型查询分类
文件上传
新增菜品
文件上传接口开发:
@RestController 是@controller和@ResponseBody 的结合
@Controller 将当前修饰的类注入SpringBoot IOC容器,使得从该类所在的项目跑起来的过程中,这个类就被实例化。 @ResponseBody 它的作用简短截说就是指该类中所有的API接口返回的数据,甭管你对应的方法返回Map或是其他Object,它会以Json字符串的形式返回给客户端
阿里云对象存储OSS
解决阿里云对象存储在java中的配置(包括配置文件,Oss工具类,将工具类实例化,导入)
回到commonController继续代码编写,upload方法uuid防止文件重命名
图片上传完成。
@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。在使用@Autowired之前,我们对一个bean配置起属性时,是这用用的
通过这种方式来,配置比较繁琐,而且代码比较多。
@Transactional 能保证方法内多个数据库操作要么同时成功、要么同时失败。
使用时要记得在启动类打开注解方式的事务管理
处理菜品sql时要处理sql语句xml配置,返回主键的值赋给id,在Service里可以get获得id,为接下来的口味准备数据。
返回生成主键 返回到id这个值上insert into dish (name,category_id,price,image,description,create_time,update_time,create_user,updte_user,status) value (#{name},#{categoryId},#{price},#,#{image},#{description},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})
还有Lambda表达式的内容。
在阿里云OSS记得把权限改为公共读,不然无法调用程序读上传的照片进行回显。
第一个问题:检测传入的DishMapper为空。
解决:排查后发现未加入@Autowired注解,所以在Spring中找不到
第二个问题:Parameter index out of range (4 > number of parameters, which is 3).
解决:发现是sql语句中,多打了一个 ,# 导致在传入第四个值时找不到对应的第四个占位符。
第三个问题:Unknown column 'updte_user' in 'field list'
解决:依然是sql语句编写问题,改为 update_user,打错字了
一般类查询操作,接口,传入传出,涉及多张表
1设计DTO接受前端传来的数据
2还要设计对应的VO(因为有categoryId这个数据)
sql的编写还是重点
问题:测试发现查询为空,什么都没有?
解决:排查发现DishController里面分页查询方法的返回值为默认的null,当然啥都查不出来
接口设计:
传入只需要一个包含id的数组
传入的id数组是json格式,可以用字符串接受,自己去拆解,也可以借助MVC帮助我们直接得到一个数组
动态sql的编写和将sql写入java都是对我来说的难点
错误:sql语句忘记加右括号
有回显需求
接口设计:
1根据id查询菜品
2根据类型查询分类1
3文件上传1
4修改菜品
1根据id查询菜品
重点是DishVo是返回对象,除了用BeanUtils复制dish属性以外还要手动设置设置dish里没有的flavor属性
2.修改菜品
sql中对于可能导致多种结结果的编写很难想到(口味先全部删除,再修改)
一次成功
感谢:业务逻辑中的增删改查并不是有手就行,sql的编写,如何让程序更高效,如何符合传入传出的数据要求,解决问题的思路和逻辑,都很重要
分析产品原型和表结构--编写时候要从全局考虑复用,尽可能高内聚。
代码编写,自己慢慢写
发现问题,新建套餐时候增加菜品按照名字搜索功能未完善。
测试出现问题:无法自动装配/未找到“XXX“类型的Bean
解决:百度发现是自己ServiceImpl上没有加@Service注解,第一次实践,不知道@Service注解加在ServiceImpl上.....
问题:小问题不断,几乎全是sql语句的编写错误,这是我的不足之处
测试完成,新增套餐接口实现成功。
编写完毕,重点是PageHelper的使用和传入值返回值的提前设置。
@RequestParam:把请求中的指定名称的参数传递给控制器中的形参赋值
测试成功一部分,单个停售商品删除成功
全写完再测试//TODO
谔谔,资料有一部分没有,只能靠自己照着之前的修改来写了
错误:sql编写出错,在set语句后没加, 这是基础知识不扎实的问题,sql真的很重要
自行编写测试通过~
路径参数和地址栏传参数:
路径参数就是@PathVariable那个,地址栏传参是Query,可以不用@RequestParam,但是要保证传参和controller中接受的参数名字一样
基于!内存存储!的key-value结构的数据库
mysql是磁盘存储(介质不同,存储结构不同-sql是表结构)
1Redis基于内存存储,读写性能高,但是内存有限
2存储热点数据(热点商品,新闻,资讯)-访问量大的时间段或者服务
复习了一下redis命令行操作
(图形界面链接需要服务端开启)
Mysql中对不同数据类型,类似插入这种命令相同,都是insert,但是Redis则不一样,不同数据类型,插入命令不同。
SDR是对前两者的高度封装
测试编写:
需要@Autowried自动注入引入的类
注意用@SpringVootTest注解引入上下文
@SpringBootTest:注解可以用来标记一个测试类,它告诉Spring Boot启动一个完整的应用程序上下文,而不仅仅是一个单一的测试类或测试方法。这个完整的应用程序上下文将包含所有的Spring Bean、配置和依赖项,这样我们就可以像在实际的应用程序中一样运行我们的测试用例。
问题:nested exception is io.lettuce.core.RedisConnectionException: Unable to conn
Client sent AUTH, but no password is set
redis的图形化界面连接时配置了密码,如果服务端没有设置密码,可以直接连接数据库,如果服务端设置了密码,假如配置密码正确,可以验证后进入。
但是Java中配置类,如果服务端设置密码,java配置文件没写密码,报错,
如果服务端没设置密码,java配置类写了密码,也报错连接错误,错误提示不需身份验证。
接口设计
为了一个数据做一张表不太值得
所以用基于redis的字符串存储
用户端和管理端路径请求不同所以分开写Controller,在两个软件包中。
注入Spring里,类名不能一样,会报冲突
Annotation-specified bean name 'shopController' for bean class [com.sky.controller.user.ShopController] conflicts with existing, non-compatible bean definition of same name and class [com.sky.controller.admin.ShopController]
解决:在Controller注解@RestController里面指定注入bean的名字
在JAVA程序中通过编码的方式来发送Http请求。
public void testGET() throws Exception { //创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建Http请求对象 HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status"); //调用方法excute发送请求 CloseableHttpResponse response = httpClient.execute(httpGet); //获取返回的状态码 int statusCode = response.getStatusLine().getStatusCode(); System.out.println("状态码:"+statusCode); HttpEntity entity = response.getEntity(); String body = EntityUtils.toString(entity); System.out.println("服务端返回数据:"+body); //关闭资源 response.close(); httpClient.close(); } /** * POST方式请求 */ @Test public void testPOST() throws Exception { CloseableHttpClient aDefault = HttpClients.createDefault(); HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login"); //构造数据 JSONObject jsonObject = new JSONObject(); jsonObject.put("username","admin"); jsonObject.put("password","123456"); //json格式转String StringEntity entity = new StringEntity(jsonObject.toString()); //设置字符编码 entity.setContentEncoding("utf-8"); //设置类型 entity.setContentType("application/json"); httpPost.setEntity(entity); //发送请求 CloseableHttpResponse response = aDefault.execute(httpPost); //解析数据 int statusCode = response.getStatusLine().getStatusCode(); System.out.println("状态码:"+statusCode); HttpEntity entity1 = response.getEntity(); String body = EntityUtils.toString(entity1); System.out.println("响应数据:"+body); //关闭数据 response.close(); aDefault.close(); }
在开发中可以直接调用封装好的工具类
(前端开发)
导入后记得修改配置.
小程序文档
Postman接口功能测试
基于微信登录实现小程序的登录功能
如果是新用户需要自动完成注册
接口设计分析
其他步骤类似,不过需要加入为用户生成jwt令牌来通过后端的拦截器.
后端还要再写一个拦截器专门用来处理用户端发送的请求,需要把拦截器注入到配置里面
注:这里的前后端联调中的前端是微信小程序端,其他和之前类似。
关键是要按照微信小程序的规定与约束进行登录功能,得到数据后存储到sql数据库,再进行相关操作。
前后端联调~
新奇的体验
增删改查
接口设计:
业务规范:
这是业务必不可少的地方
按部就班
困扰了半小时的问题:
小程序前端请求后status请求并没有被拦截器忽略,而是正常验证token,但此时并没有登录所以没有token,报错token1为空;
解决:排除摸索看评论后发现问题出在注册拦截器的环节:
registry.addInterceptor(jwtTokenUserInterceptor) .addPathPatterns("/user/**") .excludePathPatterns("/user/user/login") .excludePathPatterns("/user/shop/status");后两个user前面没写/!!!!!
比较遗憾的是并不是自己耐心排查出来的......心性还需要磨练,发现问题,仔细排查,解决问题,希望接下来的工作生活中能沉得住气。
访问量过大,数据库的访问压力随之增大,查询性能下降-----系统响应慢,用户体验差,很多时候都是出在数据库这一端
解决:通过Reidis来缓存菜品数据,减少数据库查询操作
java和redis中的数据类型并不完全一样,java中的任何数据类型可以转化为字符串存储在redis的value的位置。
1.每个分类下的菜品保存一份缓存数据
2.数据库中菜品数据有变更时及时清理缓存数据
为什么写在Controller层不是Service层?
因为service可能涉及到多个表一起操作,这个类似于在最外层过滤操作一次,层次不一样。
发现修改菜品后缓存并不清楚
解决:排查问题代码发现是传入的模式"dish_"忘记加通配符*
@Cacheable涉及到一个代理对象,由代理对象先进行缓存查询
@CacheEvict伴随着sql删除而删除
在对应的Controller方法加上注解即可。
测试无误
老三样,接口设计,传入数据选择,返回数据分析。
购物车中的商品存在,执行update更新数量。
无误
完成
稀松平常的CRUD
不同业务不同要求,不同代码编写,整体上不难,需要思考,或者经验。
下单后订单通知商家进行备货。
接口设计,数据库设计,很重要
重复工作就不写了,纯纯CRUD码农,没前途,会了
看看就行了,面试根本涉及不到?完全是微信支付的文档内容。
内网穿透工具可能得看看
大致看了一遍,除了百度地图的调用比较新颖,其他还是增删改查,业务复杂度不一,非目前首要目标。
Spring框架提供任务调度工具,可以按照约定的时间自动执行某个代码逻辑。
作用:定时自动执行某段Java代码。
场景:
信用卡还款提醒(短信)
银行贷款每月还款提醒
火车票售票系统处理未支付订单
入职纪念日发送通知
一切需要判断条件,定时执行的程序。。。。
本质上是字符串,通过cron表达式可以定义任务触发的时间
Http网络协议和WebSocket协议
视频弹幕,网页聊天,体育实况更新,股票基金报价实时更新
服务端最重要的是WebSocketService.
前端技术Apache Echarts.
JS实现表格
数据查询是大头,SQL绝对的重中之重。
常用API可以直接看文档使用。
完结撒花~