• [技术干货] 【Spring MVC】快速学习使用Spring MVC的注解及三层架构-转载
     Spring Web MVC 一: 什么是Spring Web MVC? SpringWebMVC是基于ServletAPI构建的原始Web框架,从⼀开始就包含在Spring框架中。它的正式名称“SpringWebMVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为)SpringMVC). MVC是⼀种架构设计模式,也⼀种思想,⽽SpringMVC是对MVC思想的具体实现.除此之外,SpringMVC还是⼀个Web框架. 总结来说,SpringMVC是⼀个实现了MVC模式的Web框架  MVC的定义 MVC是ModelViewController的缩写,它是软件⼯程中的⼀种软件架构设计模式,它把软件系统分 为模型、视图和控制器三个基本部分  • View(视图)指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源. • Model(模型)是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分. • Controller(控制器)可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型 来处理,以及处理完后需要跳回到哪⼀个视图。即⽤来连接视图和模型  二:Spring MVC中常用注解的使用 2.1 @RequestMapping:地址映射 @RequestMapping既可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类路径+⽅ 法路径. @RequestMapping标识⼀个类:设置映射请求的请求路径的初始信息 @RequestMapping标识⼀个⽅法:设置映射请求请求路径的具体信息  @RequestMapping("/user") @RestController public class UserController {     @RequestMapping("/sayHi")     public String sayHi(){     return "hello,Spring MVC";     } } 2.2 @RequestBody:请求正文 RequestBody:请求正⽂,意思是这个注解作⽤在请求正⽂的数据绑定,请求参数必须在写在请求正 ⽂中  @RequestMapping(value = "/m7") public Object method7(@RequestBody Person person) {     return person.toString(); } 2.3 @PathVariable:路径变量 pathvariable:路径变量 和字⾯表达的意思⼀样,这个注解主要作⽤在请求URL路径上的数据绑定 默认传递参数写在URL上,SpringMVC就可以获取到 后端实现代码:  @RequestMapping("/m8/{id}/{name}") public String method8(@PathVariable Integer id, @PathVariable("name") StringuserName){         return "解析参数id:"+id+",name:"+userName; } 如果⽅法参数名称和需要绑定的URL中的变量名称⼀致时,可以简写,不⽤给@PathVariable的属性赋 值,如上述例⼦中的id变量 如果⽅法参数名称和需要绑定的URL中的变量名称不⼀致时,需要@PathVariable的属性value赋值, 如上述例⼦中的userName变量  2.4 @RequestPart:上传文件 RequestPart主要是用于客户端上传文件交给服务器进行处理 后端代码实现:  @RequestMapping("/m9") public String getfile(@RequestPart("file") MultipartFile file) throwsIOException {     //获取⽂件名称         String fileName = file.getOriginalFilename();     //⽂件上传到指定路径         file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));         return "接收到⽂件名称为: "+fileName; } 2.5 @RequestParam:重命名 某些特殊的情况下,前端传递的参数key和我们后端接收的key可以不⼀致,⽐如前端传递了⼀个 time给后端,⽽后端是使⽤createtime字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值 后端实现代码:  @RequestMapping("/m4") public Object method_4(@RequestParam("time") String createtime) {         return "接收到参数createtime:" + createtime; } 可以得出结论:  使⽤ @RequestParam 进⾏参数重命名时,请求参数只能和 @RequestParam 声明的名称⼀ 致,才能进⾏参数绑定和赋值. 使⽤ @RequestParam 进⾏参数重命名时,参数就变成了必传参数. 2.6 @RestController:数据控制器 是Contronller和ResponseBody的封装,用于返回数据同时能够将注解内容交给Spring进行管理 @RestController = @Controller + @ResponseBody @Controller :定义⼀个控制器,Spring框架启动时加载,把这个对象交给Spring管理. @ResponseBody :定义返回的数据格式为⾮视图,返回⼀个text/html信息  2.7 @ResponseBody:数据格式 @ResponseBody :定义返回的数据格式为⾮视图,返回⼀个text/html信息  @ResponseBody public class IndexController {     @RequestMapping("/index")         public Object index(){         return "/index.html";     } } @ResponseBody 既是类注解,⼜是⽅法注解 如果作⽤在类上,表⽰该类的所有⽅法,返回的都是数据,如果作⽤在⽅法上,表⽰该⽅法返回的是数据. 也就是说:在类上添加 @ResponseBody 就相当于在所有的⽅法上添加了 @ResponseBody 注解. 同样,如果类上有 @RestController 注解时:表⽰所有的⽅法上添加了 @ResponseBody 注 解,也就是当前类下所有的⽅法返回值做为响应数据 设置状态码 SpringMVC会根据我们⽅法的返回结果⾃动设置响应状态码,程序员也可以⼿动指定状态码 通过SpringMVC的内置对象HttpServletResponse提供的⽅法来进⾏设置      @ResponseBody     public String setStatus(HttpServletResponse response) {         response.setStatus(401);         return "设置状态码成功";     } 2.8 @CookieValue:获取Cookie Cook是用户客户端用于保存用户的基本信息,以便于用户在下一次登录时可以直接进入  @RequestMapping("/getCookie") public String cookie(@CookieValue("bite") String bite) {     return "bite:" + bite; } 2.9 @SessionAttribute:获取Session Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象  Session的本质就是⼀个"哈希表",存储了⼀些键值对结构.Key就是SessionID,Value就是⽤⼾信息(⽤ ⼾信息可以根据需求灵活设计). SessionId是由服务器⽣成的⼀个"唯⼀性字符串",从Session机制的⻆度来看,这个唯⼀性字符串称 为)SessionId).但是站在整个登录流程中看待,也可以把这个唯⼀性字符串称为)token).  当⽤⼾登陆的时候,服务器在Session中新增⼀个新记录,并把sessionId返回给客⼾端.(通过 HTTP响应中的Set-Cookie字段返回). 客⼾端后续再给服务器发送请求的时候,需要在请求中带上sessionId.(通过HTTP请求中的 Cookie字段带上). 服务器收到请求之后,根据请求中的sessionId在Session信息中获取到对应的⽤⼾信息,再进⾏后 续操作.找不到则重新创建Session,并把SessionID返回 @RequestMapping("/getSess2") public String sess2(@SessionAttribute(value = "username",required = false)String username) {         return "username:"+username; } Cookie和Session的区别 • Cookie是客⼾端保存⽤⼾信息的⼀种机制.Session是服务器端保存⽤⼾信息的⼀种机制. • Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Cookie和Session之间的 桥梁 • Cookie和Session经常会在⼀起配合使⽤.但是不是必须配合. ◦ 完全可以⽤Cookie来保存⼀些数据在客⼾端.这些数据不⼀定是⽤⼾⾝份信息,也不⼀定是 SessionId ◦ Session中的sessionId也不需要⾮得通过Cookie/Set-Cookie传递,⽐如通过URL传递.  2.10 @Data:类注解 Lombok是⼀个Java⼯具库,通过添加注解的⽅式,简化Java的开发其中@Data 注解会帮助我们⾃动⼀些⽅法,包含getter/setter,equals,toString等 Lombok的作⽤如下图所⽰:  如果觉得@Data⽐较粗暴(⽣成⽅法太多),lombok也提供了⼀些更精细粒度的注解  注解    作⽤ @Getter    ⾃动添加getter⽅法 @Setter    ⾃动添加setter⽅法 @ToString    ⾃动添加toString⽅法 @EqualsAndHashCode    ⾃动添加equals和hashCode⽅法 @NoArgsConstructor    ⾃动添加⽆参构造⽅法 @AllArgsConstructor    ⾃动添加全属性构造⽅法,顺序按照属性的定义顺序 @NonNull    属性不能为null @RequiredArgsConstructor    ⾃动添加必需属性的构造⽅法,final+@NonNull的属性为必需 @Data=@Getter+@Setter+@ToString+@EqualsAndHashCode+@RequiredArgsConstructor+@NoArgsConstructor 因此可以说明在创建类对象时可以通过引入lambok工具包中的@Data注解,可以自动为我们添加其很多常用的赋值方法  三:应用分层-三层架构 ⽬前现在更主流的开发⽅式是"前后端分离"的⽅式,后端开发⼯程师不再需要关注前端的实现,所以对 于Java后端开发者,⼜有了⼀种新的分层架构:把整体架构分为表现层、业务逻辑层和数据层.这种分层 ⽅式也称之为"三层架构".  表现层:就是展⽰数据结果和接受⽤⼾指令的,是最靠近⽤⼾的⼀层; 业务逻辑层:负责处理业务逻辑,⾥⾯有复杂业务的具体实现; 数据层:负责存储和管理与应⽤程序相关的数据 可以看到,咱们前⾯的代码,并不符合这种设计思想,⽽是所有的代码堆砌在⼀起 按照上⾯的层次划分,SpringMVC站在后端开发⼈员的⻆度上,也进⾏了⽀持, • 请求处理、响应数据:负责,接收⻚⾯的请求,给⻚⾯响应数据. • 逻辑处理:负责业务逻辑处理的代码. • 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作  • Controller:控制层。接收前端发送的请求,对请求进⾏处理,并响应数据。 • Service:业务逻辑层。处理具体的业务逻辑。 • Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查 MVC和三层架构的区别和联系 关于⼆者的关系,⼀直存在不同的观点.有⼈认为三层架构是MVC模式的⼀种实现,也有⼈认为MVC是 三层架构的替代⽅案,等等各种说法都有.根本原因是⼤家站在不同的⻆度来看待这个问题的. JavaEE部分的学习重在"实践",⼤家根据⾃⼰的理解,能够⾃圆其说,说出⾃⼰的观点即可,也不建议 ⼤家去背书.  从概念上来讲,⼆者都是软件⼯程领域中的架构模式. MVC架构模式由三部分组成,分别是:模型(Model),视图(View)和控制器(Controller). 三层架构将业务应⽤划分为:表现层,业务逻辑层,数据访问层.  MVC中,视图和控制器合起来对应三层架构中的表现层.模型对应三层架构中的业务逻辑层,数据层, 以及实体类 ⼆者其实是从不同⻆度对软件⼯程进⾏了抽象. MVC模式强调数据和视图分离,将数据展⽰和数据处理分开,通过控制器对两者进⾏组合. 三层架构强调不同维度数据处理的⾼内聚和低耦合,将交互界⾯,业务处理和数据库操作的逻辑分开. ⻆度不同也就谈不上互相替代了,在⽇常的开发中可以经常看到两种共存的情况,⽐如我们设计模型 层的时候往往也会拆分出业务逻辑层(Service层)和数据访问层(Dao层)  四:总结 1.学习SpringMVC,其实就是学习各种Web开发需要⽤的到注解 a. @RequestMapping:路由映射 b. @RequestParam:后端参数重命名 c. @RequestBody:接收JSON类型的参数 d. @PathVariable:接收路径参数 e. @RequestPart:上传⽂件 f. @ResponseBody:返回数据 g. @CookieValue:从Cookie中获取值 h. @SessionAttribute:从Session中获取值 i. @RequestHeader:从Header中获取值 j. @Controller:定义⼀个控制器,Spring框架启动时加载,把这个对象交给Spring管理.默认返回 视图. k. @RestController:@ResponseBody+@Controller返回数据 2. Cookie和Session都是会话机制,Cookie是客⼾端机制,Session是服务端机制.⼆者通过SessionId 来关联.SpringMVC内置HttpServletRequest,HttpServletResponse两个对象.需要使⽤时,直接在 ⽅法中添加对应参数即可,Cookie和Session可以从HttpServletRequest中来获取,也可以直接使⽤ HttpServletResponse设置Http响应状态码. ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/smile_sundays/article/details/137207581 
  • [技术干货] 4套java开发的智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码3D 智能导诊系统源码
    4套java开发的智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码3D 智能导诊系统源码Java智慧校园系统源码 智慧学校源码 微信小程序+电子班牌智慧校园系统简介:智慧校园的建设逐渐被师生、家长认可接受,智慧校园通过对在校师生、教务等所有人员的信息以及各种信息搜集与储存,进行数据优化与管理,为师生们提供更加智能化的校园服务。未来智慧校园将不再是一个陌生词,而会真正地应用在更多的校园管理中,让我们的校园生活变得更加美好。系统源码技术说明:后端:Java   框架:springboot  +前端页面:vue  小程序+小程序原生开发+电子班牌:Java Android移动家长端应用:通知管理、图片管理、班级考勤、综合素质评价、视频管理、请假管理、成绩管理、个人信息、进离校管理、教师通讯录、家长留言、课堂点名、家长会签到、活动报名、放学管理、学生评价。移动教师端应用:设备管理、通知管理、图片管理、班级考勤、综合素质评价、视频管理、请假管理、成绩管理、个人信息、进离校管理、家长通讯录、教师通讯录、教师课表、AI智能分析、课堂点名、课堂授课、家长会签到、活动报名、积分商城、倒计时、班级德育、体温检测、放学管理、学生评价。Java智慧工地源码 智慧工地监管平台源码 SaaS模式PC端+手机端+平板端智慧工地系统简介:智慧工地是指利用移动互联、物联网、智能算法、地理信息系统、大数据挖掘分析等信息技术,提高项目现场的“人•机•料•法•环•安”等施工要素信息化管理水平,实现工程施工可视化智能管理,并逐步实现绿色生态建造。系统源码技术说明:微服务架构+Java+Spring Cloud +UniApp +MySql,支持多端展示(PC端、手机端、平板端);数字孪生可视化大屏,一张图掌握项目整体情况;使用轻量化模型,部署三维可视化管理,与一线生产过程相融合,集成数据后台,统一前端入口,呈现多方项目信息;用户PC端、移动端数据同步,依托组件化开发平台。;依托数据交互子平台,形成用户多系统间数据融合;依托智慧工地平台,满足省、市级住建数据监管要求;利用5G及智能终端算法,实现IOT设备数据抓取与处理。Java智慧城管系统源码 城管智慧执法系统源码 数字城管APP系统源码 城市管理综合执法监督系统源码智慧城管系统简介:智慧城管系统是一个基于现代信息技术手段的综合管理平台,旨在通过强化信息获取自动化、监督管理精细化、业务职能协同化、服务手段多样化、辅助决策智能化以及执法手段人性化,实现城市管理要素、管理过程和管理决策的全方位智慧化。具体来说,智慧城管系统充分利用物联网、云计算、信息融合、网络通讯、数据分析与挖掘等技术,对城市管理进行全方位覆盖。它通过建立城市综合管理平台,将城市的信息和管理资源有机结合起来,实现城管执法、市容环卫、市政设施、园林绿化等业务的数字化和网络化。该系统不仅提高了城市管理的科学化水平,还促进了市容环境和城市形象的改善。城管综合执法监督系统是一个综合性的管理平台,旨在提高城市管理的效率和质量,确保执法活动的公开、公正和透明。该系统通过整合各种资源和信息,实现对城管执法活动的全面监督和管理。系统源码技术说明:微服务+开发语言: java+开发工具:idea、VSCode+前端框架:vue+element+后端框架:springboot+数 据 库:mysql5.7+移 动 端:uniapp功能模块本系统共分为七个模块:首页、执法办案、视频智能分析、统计分析、执法队伍、基础支撑、系统管理;首页模块下包含:待办事项、常用功能、通知公告、简易案件、普通案件、案由库、法律法规、文书模板;执法办案模块下包含:我的待办、线索管理、管理事件、简易案件、普通案件、重大案件会办、车辆违停管理、当事人管理;视频智能分析模块下包含:市容违规、监控配置;统计分析模块下包含:线索案件统计、事案件分析、上报数据分析、事案件区域统计、AI 视频识别分析、考勤统计;执法队伍模块下包含:执法调度、考勤管理、机构管理、人员管理;基础支撑模块下包含:文书管理、法律法规、案由库、通知公告;系统管理模块下包含:执法设置、菜单管理、字典管理、参数管理、日志管理、角色管理;java智慧导诊系统源码 互联网智能3D导诊系统源码 智慧医院导诊系统源码 智慧导诊系统简介:智慧导诊解决患者盲目就诊问题,减轻分诊工作压力。降低患者挂错号比例,优化患者就诊流程,有效提高线上线下医疗机构接诊效率。患者可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。系统源码技术说明:技术架构:springboot+redis+mybatis plus+mysql+RocketMQ+开发语言:java+开发工具:IDEA+前端框架:Uniapp+后端框架:springboot+数 据 库:mysql+移 动 端:微信小程序、H5应用场景:1.智慧医院:帮助患者判断应挂号科室,降低科室间转诊率:帮助医院导诊工作人员接待挂号相关问题,对接医院挂号系统,完成导诊后可直接挂号2.互联网医院:帮助患者判断应挂号科室,降低科室间转诊率,标准科室对照,精准分配在线问诊科室3.医疗健康平台:为平台赋能,向患者提供标准科室就诊建议,标准科室对照,精准分配在线问诊科室
  • [技术干货] CORS就是跨域吗【转】
    首先,跨域的域是什么?跨域的英文是:Cross-Origin。Origin 中文含义为:起源,源头,出生地。在跨域中,"域"指的是一个 Web 资源(比如网页、脚本、图片等)的源头。包括该资源的协议、主机名、端口号。在同源策略中,如果两个资源的域相同,则它们属于同一域,可以自由进行交互和共享数据。反之,如果两个资源的域不同,就会出现跨域问题。这时就需要特殊的方式来处理,如跨域资源共享(CORS)。那什么是同源策略?同源策略(Same-Origin Policy)是浏览器中的一项安全机制,用于保护用户的隐私和安全。它限制了一个网页或者脚本只能从同一个源加载的资源进行访问,而不能访问其他来源的资源。这样做可以防止恶意网站利用用户身份信息进行跨站请求伪造(CSRF)攻击,保护用户的数据安全。什么是跨站请求伪造?跨站请求伪造(CSRF,Cross-Site Request Forgery)是一种网络攻击方式。在 CSRF 攻击中,攻击者利用已认证的用户身份(例如用户在银行网站上登录后的会话信息)来伪造请求,以执行未经授权的操作。举个例子:我登录了银行网站,浏览器根据我的登录信息生成了一个会话令牌,也就是 session token。但是这个令牌被而恶意网站给拿到了,它拿着我的 token 去服务器发送请求。就可以把我银行卡里的 29 块八毛五全部转走。但是如果有同源策略的限制,恶意网站就无法直接发送请求到银行。我的 29 块八毛五就可以保住。因为恶意网站的域名与银行网站的域名不同,浏览器会阻止这种抢劫行为。什么是跨域资源共享(CORS)?为了防止被面试官笑话,这里一定要知道:跨域资源共享(CORS,Cross-Origin Resource Sharing)是一种用来解决由于浏览器的同源策略而导致的跨域请求问题的一种机制。浏览器将 CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。什么是简单请求?只要同时满足以下两大条件,就属于简单请求。(1)请求方法是以下三种方法之一: - HEAD - GET - POST (2)HTTP的头信息不超出以下几种字段: - Accept - Accept-Language - Content-Language - Last-Event-ID - Content-Type:只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain简单请求的工作流程如下:1. 浏览器在请求中增加一个 Origin 头部字段,其中包含当前页面的源信息(协议、主机、端口)。2. 服务器在收到这个请求后,会根据请求中的 Origin 头部信息来判断是否允许该请求。3. 如果服务器允许该请求,会在响应头部中包含一个 Access-Control-Allow-Origin 头部,"*"表示允许所有来源。4. 浏览器在收到响应后,决定是否允许页面访问该资源。什么是非简单请求?不是简单请求的,就是非简单请求。非简单请求它非简单在哪?或者说:它非简单又能怎么样?非简单请求在发起正式请求之前,会先发起一个预检请求。什么是预检请求?预检请求是用于在实际的跨域请求之前进行探测和验证,以确保服务器能够正确处理,预防跨域请求可能会引发的安全性问题。一句话就是:我去前面探探路!只有得到服务器的肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。实际 java 开发中的 CORS 解决跨域配置长这样:@Configuration public class CorsConfig implements WebMvcConfigurer {     @Override     public void addCorsMappings(CorsRegistry registry) {         // 允许所有的URL路径都可以跨域访问         registry.addMapping("/**")             // 允许所有来源(即允许任何域名)的请求跨域访问             .allowedOrigins("*")             // 允许发送身份验证信息(如cookies、HTTP身份验证或客户端SSL证明)             .allowCredentials(true)             // 允许跨域请求的HTTP方法,包括GET、POST、PUT、DELETE和OPTIONS。             .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")             // 预检请求(OPTIONS请求)的有效期,单位为秒             .maxAge(3600);     } }还有别的方式可以解决跨域问题吗?有的。使用 Nginx 部署为同一域。什么意思呢?就是说 Nginx 作为唯一域,代理所有服务端,在客户端眼里,只有 Nginx 这一个域,也就不存在跨域问题,由 Nginx 拿到请求再分发给对应服务器。这里我们就不再展开。转载自https://www.cnblogs.com/cosimo/p/18023596
  • [技术干货] 【SpringBoot篇】登录校验 — JWT令牌-转载
     🌹简述JWT令牌 JWT全称为JSON Web Token,是一种用于身份验证的开放标准。它是一个基于JSON格式的安全令牌,主要用于在网络上传输声明或者用户身份信息。JWT通常被用作API的认证方式,以及跨域身份验证。  JWT令牌由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature)。头部包含了令牌使用的加密算法信息,载荷包含了所需传输的用户信息,签名用于保证令牌的完整性和真实性,防止令牌被篡改。   官网https://jwt.io/  ⭐JWT特点 可以跨语言、跨平台使用,因为它是基于JSON标准的。 可以直接嵌入到HTTP请求头中,方便传输和验证。 令牌的有效期可以通过设置过期时间来进行控制,提高了安全性。 由于令牌中包含了用户信息,因此可以避免频繁查询数据库的情况出现,提高了系统的性能。 🌺JWT使用流程 用户向服务器发送登录请求,服务器进行身份验证,如果验证成功则返回一个JWT令牌给客户端。  客户端收到JWT令牌后,将其保存在本地。每次向服务器发送请求时,在请求的头部中携带该令牌,以便服务器对请求进行身份验证。  服务器收到请求后,从请求头中提取JWT令牌,并进行解析和验证。如果令牌有效,则允许请求继续执行;否则返回错误信息。  生成令牌,校验令牌  在服务端拦截所有的请求,判断算法有合法的jwt请求,如果有,直接放行,否则进行拦截  🛸JWT令牌代码实现 我把代码脚手架传到网盘里面了,大家跟着代码来学习 我用夸克网盘分享了「tlias-web-management」,点击链接即可保存。 链接:https://pan.quark.cn/s/1f4f6c129be8  添加依赖  <!--        JWT令牌-->         <dependency>             <groupId>io.jsonwebtoken</groupId>             <artifactId>jjwt</artifactId>             <version>0.9.1</version>         </dependency> 生成JWT令牌   //生成jwt     @Test     public void testGenJwt(){         Map<String, Object> claims = new HashMap<>();         claims.put("id",1);         claims.put("name","Tom");          String jwt = Jwts.builder()                 .signWith(SignatureAlgorithm.HS512, "itheima")  //签名算法                 .setClaims(claims)   //自定义内容                                 //有参构造方法                 .setExpiration(new Date(System.currentTimeMillis()+3600))  //令牌过期时间                .compact();         System.out.println(jwt);      }  运行后发现,出现了jwt令牌  我们把这一段jwt令牌复制粘贴到jwt官网进行解析一下  https://jwt.io/  解析jwt令牌 (相当于校验令牌,只要解析令牌不报错,就相当于校验jwt令牌正确)     //解析jwt     @Test     public void testParseJwt() {         Claims claims=Jwts.parser()                 .setSigningKey("itheima")                 //写入你刚才运行出来的jwt令牌                 .parseClaimsJws("eyJhbGciOiJIUzUxMiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTcwMDcyMzQ1M30.GMp1Z-osnaOJ08nM3uswPKRFIaKS4e6_UvZXq2Q4QjYBFRcJNk7WgQRkFJHXIUrZfKovXUZhd8-OOKtXYDyrbg")                 .getBody();         System.out.println(claims);     } 解析出来了 可能会发生这种报错,是因为jwt令牌过期了,重新生成一个即可  🍔JWT应用 我们接着上面的代码写,引入jwt工具类   package com.itheima.utils;  import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm;  import java.util.Date; import java.util.Map;  public class JwtUtils {      private static String signKey = "itheima";    //签名密钥     private static Long expire = 43200000L;        //过期时间      /**      * 生成JWT令牌      * @param claims JWT第二部分负载 payload 中存储的内容      * @return      */     public static String generateJwt(Map<String, Object> claims){         String jwt = Jwts.builder()                 .addClaims(claims)                 .signWith(SignatureAlgorithm.HS256, signKey)                 .setExpiration(new Date(System.currentTimeMillis() + expire))                 .compact();         return jwt;     }      /**      * 解析JWT令牌      * @param jwt JWT令牌      * @return JWT第二部分负载 payload 中存储的内容      */     public static Claims parseJWT(String jwt){         Claims claims = Jwts.parser()                 .setSigningKey(signKey)                 .parseClaimsJws(jwt)                 .getBody();         return claims;     } } 创建LoginController,里面包含了生成jwt令牌的代码  package com.itheima.controller;  import com.itheima.pojo.Emp; import com.itheima.pojo.Result; import com.itheima.service.EmpService; import com.itheima.utils.JwtUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;  import java.util.HashMap; import java.util.Map;  @Slf4j @RestController public class LoginController {      @Autowired     private EmpService empService;      @PostMapping("/login")     public Result login(@RequestBody Emp emp){         log.info("员工登录: {}", emp);         Emp e = empService.login(emp);          //登录成功,生成令牌,下发令牌         if (e != null){             Map<String, Object> claims = new HashMap<>();             claims.put("id", e.getId());             claims.put("name", e.getName());             claims.put("username", e.getUsername());              String jwt = JwtUtils.generateJwt(claims); //jwt包含了当前登录的员工信息             return Result.success(jwt);         }          //登录失败, 返回错误信息         return Result.error("用户名或密码错误");     }  } 在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天! ———————————————— 版权声明:本文为CSDN博主「在下小吉.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/m0_72853403/article/details/134686838 
  • [技术干货] Spring 中对 controller和service层的一些见解
    接触Spring Boot开发一年不到,回想起前几年使用spring MVC的时候,因为当时公司业务比较简单,所以service层和dao层实际上是一样的,业务逻辑全部放在了controller层来做;当时觉得很纳闷,service层感觉是多余的,根本用不到;最近接触的项目,架构师设计的框架,直接根据模型设计dao层接口和service接口,代码写了不少,突然发现这么定义接口很多功能是没法实现的。于是回头重新思考了spring MVC模型,刚才看了篇 非常不错的博客 ,感觉作者能把这个问题解释清楚了。还是从MVC三层模型开始,这三层模型的设计之初,就是为了将业务层(controller)、视图层(view)以及模型层(modal)区分开来。需要注意的是,这里并没有数据库这个概念,所以模型层会有一些冗杂,两个表的联合查询出来的数据,会被封装成一个模型交给控制层;同样的,控制层因为没有服务的概念,如果项目比较大,也会变的有些冗余。基于controller和modal层并没有很好的实现模块化,因此,我们将modal层去掉,改为更加原子化的dao层;同时,将controller层的业务逻辑,划分成多个服务(service)。每个服务可以组合使用dao层数据,组装成一个服务,比如用户的注册服务;而controller层,调用多个service服务完成url请求。简单来说,增加service层,替换modal层,第一是细化了数据模型,使得我们在改动某张表时,只需要改动dao层实现即可,最大化的减少了代码的改动成本;当然,更多的情况是service服务和controller可能都需要更改; service层将controller的逻辑分类,保证了controller的逻辑更加清晰。举个生活中的例子,用户预约某个酒店的客房,这是酒店首先会调用验证服务对用户提供的信息进行验证,之后调用预约服务进行预约,如果预约失败,酒店可能会把客户的预约信息提交给另外一家酒店请求它们的预约服务,然后将结果返回给客户;对于服务层来说,需要判断酒店是否有空余客房,之后修改客房信息,同时将客房和用户信息存入临时表。这里至少需要两种不同的dao层服务实现service。所以整体上来看,controllrt->service->dao至少是一对一,更多的情况下是一对多。这也就是service层存在的意义了。