【开源项目--稻草】Day04

【开源项目--稻草】Day04

  • 1. 续 VUE
    • 1.1 完善VUE+AJAX完成注册功能
  • Spring验证框架
    • 什么是Spring验证框架
    • 使用Spring-Validation
  • 稻草问答-学生首页
    • 显示首页
    • 制作首页的流程
    • 开发标签列表
      • 标签列表显示原理
    • 从业务逻辑层开始
    • 编写控制层代码
    • 开发问题列表
      • 开发业务逻辑层
      • 开发页面和JS代码显示问题
  • 随笔

1. 续 VUE

1.1 完善VUE+AJAX完成注册功能

我们现在注册用户只能在浏览器控制台看到结果

怎么能再注册页面上看到注册结果呢?

实际上,register.html页面已经准备好了一个显示注册信息的div

改写它代码如下

<div id="error" class="alert alert-danger"style="display: none"v-bind:class="{'d-block':hasError}"><i class="fa fa-exclamation-triangle"></i><span v-text="message">邀请码错误!</span>
</div>

其中v-bind:class="{‘d-block’:hasError}"的含义为

根据Vue代码中绑定的hasError变量来决定是否将class="d-block"加入到当前div中

如果将这个class加入得到当前div的样式中,则这个div会显示出来

页面修改后,register.js文件也要随之修改

代码如下

let app = new Vue({el:'#app',data:{inviteCode:'',phone:'',nickname:'',password:'',confirm:'',message:'',hasError:false},methods:{register:function () {console.log('Submit');let data = {inviteCode: this.inviteCode,phone: this.phone,nickname: this.nickname,password: this.password,confirm: this.confirm}console.log(data);if(data.password !== data.confirm){this.message="两次密码输入不一致";this.hasError=true;return;}$.ajax({url:"/register",method: "POST",data: data,success: function (r) {console.log(r);if(r.code == CREATED){console.log("注册成功");console.log(r.message);//注册成功,可以直接跳转到登录页location.href="/login.html?register";}else{console.log(r.message);//如果注册失败将信息显示在信息Div中app.message=r.message;app.hasError=true;}}});}}
});

新增两个属性:hasError和message

这两个属性控制页面上是否显示错误div以及错误div中出现的提示信息是什么

Spring验证框架

什么是Spring验证框架

Spring提供的对用户输入信息进行验证的框架组件

是服务器端验证技术

在这里插入图片描述

使用Spring验证框架验证发送到服务器的内容的合法性!

Spring-validation(验证)

使用Spring-Validation

步骤1:

导入依赖

子项目pom.xml文件添加:

<!-- 验证框架 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

步骤2:

定位到要验证信息的实体类

将验证规则按照给定注解来标记即可

要验证注册业务,就找RegisterVo类即可

@Data
public class RegisterVo implements Serializable {//只能作用在String上,不能为null,去掉空格之后也不能为""@NotBlank(message = "邀请码不能为空")private String inviteCode;@NotBlank(message = "用户名不能为空")//@Pattern()表示下面的属性需要通过指定正则表达式的判断@Pattern(regexp="^1\\d{10}$",message ="手机号格式不正确")private String phone;@NotBlank(message = "昵称不能为空")@Pattern(regexp="^.{2,20}$",message ="昵称在2到20位之间")private String nickname;@NotBlank(message = "密码不能为空")@Pattern(regexp="^\\w{6,20}$",message ="密码在6~20位之间")private String password;@NotBlank(message = "确认密码不能为空")private String confirm;}

步骤3:

在控制器从表单或ajax获得实体类对象参数时就可以对这个实体类属性的值进行上面设置的验证了

验证方法非常简单,只需要加一个注解即可!

SystemController注册方法代码修改如下

@PostMapping("/register")public R registerStudent(//控制器接收的参数前加@Validated//表示要按这个类规定的验证规则,验证这个对象属性的值@Validated RegisterVo registerVo,//固定用法,在验证参数后再跟一个参数:BindingResult//这个参数中记录保存上面验证过程中的验证信息和结果BindingResult validaResult){//在控制器调用业务逻辑前,先判断BindingResult对象中是否有错误if(validaResult.hasErrors()){//如果验证结果中包含任何错误信息,进入这个if//获得其中的一个错误信息显示,一般是按顺序的第一个错误信息String error=validaResult.getFieldError().getDefaultMessage();return R.unproecsableEntity(error);}System.out.println(registerVo);log.debug("得到信息为:{}",registerVo);try{userService.registerStudent(registerVo);return R.created("注册成功!");}catch (ServiceException e){log.error("注册失败",e);return R.failed(e);}}

就可以测试验证的效果了

稻草问答-学生首页

显示首页

步骤1:

将static文件中的index.html复制到templates文件夹中

步骤2:

创建HomeController类,显示index.html

代码如下

@RestController
@Slf4j
public class HomeController {//显示首页@GetMapping("/index.html")public ModelAndView index(){return  new ModelAndView("index");}
}

步骤3:

撤销在SecurityConfig类中对index.html的放行

达到必须登录才能访问主页的效果

http.csrf().disable().authorizeRequests()//对当前全部请求进行授权.antMatchers("/img/*","/js/*","/css/*","/bower_components/**","/login.html","/register.html","/register")//设置路径.permitAll()//允许全部请求访问上面定义的路径//其它路径需要全部进行表单登录验证.anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/login").failureUrl("/login.html?error").defaultSuccessUrl("/index.html").and().logout().logoutUrl("/logout").logoutSuccessUrl("/login.html?logout");

制作首页的流程

1.制作首页导航栏的tag列表

2.制作学生问题的显示和分页

3.制作学生信息面板

开发标签列表

标签列表显示原理

在这里插入图片描述

在用户已经能够登录显示主页的前提下

  1. 主页页面中编写ajax向控制器发送请求所有标签
  2. 控制接到请求后调用业务逻辑层
  3. 业务逻辑层从tagMapper接口查询所有标签
  4. 业务逻辑层将查询到的信息返回给控制器
  5. 控制器获得所以标签返回JSON格式
  6. ajax中获得JSON对象,利用VUE绑定显示在页面上

从业务逻辑层开始

我们可以选择先编写业务逻辑层

步骤1:

ITagService接口中添加方法

public interface ITagService extends IService<Tag> {List<Tag> getTags();
}

步骤2:

实现这个接口

TagServiceImpl类中代码如下

@Service
public class TagServiceImpl extends ServiceImpl<TagMapper, Tag> implements ITagService {//CopyOnWriteArrayList<>是线程安全的集合,适合在高并发的环境下使用private final List<Tag> tags=new CopyOnWriteArrayList<>();@Overridepublic List<Tag> getTags() {//这个if主要是为了保证tags被顺利赋值之后的高效运行if(tags.isEmpty()) {synchronized (tags) {//这个if主要是为了保证不会有两条以上线程为tags重复添加内容if (tags.isEmpty()) {//super.list()是父类提供的查询当前指定实体类全部行的代码tags.addAll(super.list());}}}return tags;}
}

步骤3:

测试

@SpringBootTest
public class TagTest {@AutowiredITagService tagService;@Testpublic void test() {List<Tag> list = tagService.getTags();for (Tag tag : list)System.out.println(tag);}}

编写控制层代码

步骤1:

TagController类中编写代码如下

@RestController
//下面的注解表示想访问本控制器中的任何方法需要前缀/v1/tags
//这个v1开头的格式是后期微服务的标准名为RESTful
@RequestMapping("/v1/tags")
public class TagController {@Autowiredprivate ITagService tagService;//查询所有标签@GetMapping("")表示使用类上声明的前缀就可以访问这个方法@GetMapping("")public R<List<Tag>> tags(){List<Tag> list=tagService.getTags();return R.ok(list);}
}

步骤2:

到页面中(index.html)绑定vue需要的变量

页面代码如下

	<div class="nav font-weight-light" id="tagsApp"><a href="tag/tag_question.html" class="nav-item nav-link text-info">	<small>全部</small></a><!-- v-for 循环中in左侧是随意起的变量名,会在循环体中使用in右侧的变量名,绑定这VUE代码中的变量--><a href="tag/tag_question.html"class="nav-item nav-link text-info"v-for="tag in tags"><small v-text="tag.name">Java基础</small></a></div>

步骤3:

index.html网页的结束位置要引入两个js文件

</body>
<script src="js/utils.js"></script>
<script src="js/index.js"></script>
<script src="js/tags_nav.js"></script>
</html>

步骤4:

编写js/tags_nav.js代码如下

let tagsApp = new Vue({el:'#tagsApp',data:{tags:[]},methods:{loadTags:function () {console.log('执行了 loadTags');$.ajax({url:'/v1/tags',method:'GET',success:function (r) {console.log(r);if (r.code === OK){console.log('成功获取tags');//将从控制器获得的所有标签赋值给vue定义的//tags数组,由于双向绑定,赋值同时页面就开始循环了tagsApp.tags = r.data;}}});}},//这个方法会在页面加载完毕之后运行created:function () {//页面加载完毕,立即调用loadTagsthis.loadTags();}
});

开发问题列表

了解开发流程

在这里插入图片描述

开发业务逻辑层

步骤1:

在业务逻辑层的接口中声明方法

IQuestionService接口给中声明方法

public interface IQuestionService extends IService<Question> {//按登录用户查询当前用户问题的方法List<Question> getMyQuestions();
}

步骤2:

要想实现查询当前登录的用户信息,必须使用Spring-Security提供的指定方法

调用这个方法的代码可能在项目后面的业务中也需要

这样写字QuestionService中就不合适了,所以我们先在IUserService中添加一个获得当前登录用户名的方法

IUserService添加代码

 //从Spring-Security中获得当前登录用户的用户名的方法String currentUsername();

步骤3:

在UserServiceImpl类中实现获得当前登录用户名并返回

@Overridepublic String currentUsername() {//利用Spring-Security框架获得当前登录用户信息Authentication authentication=SecurityContextHolder.getContext().getAuthentication();//判断当前用户有没有登录,如果没有登录抛出异常if(!(authentication instanceof AnonymousAuthenticationToken)){//上面代码是判断当前用的抽象权限类型是不是匿名用户//如果不是匿名用户,就是登录的用户,只有登录的用户才能返回用户名String username=authentication.getName();return username;}//没运行上面的if证明用户没有登录,抛出异常即可throw ServiceException.notFound("没有登录");}

步骤4:

现在就可以在QuestionServiceImpl类中调用上面编写的方法来获得当前登录用户了

在根据这个用户信息(id)查询这个用户的问题

代码如下

@Service
@Slf4j
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements IQuestionService {@AutowiredIUserService userService;@AutowiredUserMapper userMapper;@AutowiredQuestionMapper questionMapper;//按登录用户查询当前用户问题的方法@Overridepublic List<Question> getMyQuestions() {//获得当前登录用户的用户名String username=userService.currentUsername();log.debug("当前登录用户为:{}",username);//如果已经登录,使用之前编写好的findUserByUsername方法//查询出当前用户的详细信息(实际上主要需要用户的id)User user=userMapper.findUserByUsername(username);if(user == null){throw ServiceException.gone("登录用户不存在");}log.debug("开始查询{}用户的问题",user.getId());QueryWrapper<Question> queryWrapper=new QueryWrapper<>();queryWrapper.eq("user_id",user.getId());queryWrapper.eq("delete_status",0);queryWrapper.orderByDesc("createtime");List<Question> list=questionMapper.selectList(queryWrapper);log.debug("当前用户的问题数量为:{}",list.size());return list;}
}

步骤5:

编写完QuestionServiceImpl类中的代码

就可以在控制器中调用了,

控制器调用无需任何参数直接调用即可

第一次打开QuestionController类编写代码如下

@RestController
@RequestMapping("/v1/questions")
@Slf4j
public class QuestionController {@AutowiredIQuestionService questionService;//查询返回当前登录用户发布的问题@GetMapping("/my")public R<List<Question>> my(){log.debug("开始查询当前用户的问题");//这里要处理个异常,因为用户可能没有登录try{List<Question> questions=questionService.getMyQuestions();return R.ok(questions);}catch (ServiceException e){log.error("用户查询问题失败!",e);return R.failed(e);}}
}

编写到这里,我们就可以向浏览器编写路径

http://localhost:8080/v1/questions/my来看到控制返回的JSON格式信息

开发页面和JS代码显示问题

步骤1:

先在index.html页面中编写VUE代码准备绑定JSON格式信息

<div class="container-fluid" id="questionsApp"><h4 class="border-bottom m-2 p-2 font-weight-light"><i class="fa fa-comments-o" aria-hidden="true"></i> 我的问答</h4><div class="row" style="display: none"><div class="alert alert-warning w-100" role="alert">抱歉您还没有提问内容, <a href="question/create.html" class="alert-link">您可以点击此处提问</a>,或者点击标签查看其它问答</div></div><div class="media bg-white m-2 p-3" v-for="question in questions" ><div class="media-body w-50"><div class="row"><div class="col-md-12 col-lg-2"><span class="badge badge-pill badge-warning" style="display: none">未回复</span><span class="badge badge-pill badge-info" style="display: none">已回复</span><span class="badge badge-pill badge-success">已解决</span></div><div class="col-md-12 col-lg-10"><h5 class="mt-0 mb-1 text-truncate"><a class="text-dark" href="question/detail.html"v-text="question.title">eclipse 如何导入项目?</a></h5></div></div><div class="font-weight-light text-truncate text-wrap text-justify mb-2" style="height: 70px;"><p v-html="question.content">eclipse 如何导入项目?</p></div><div class="row"><div class="col-12 mt-1 text-info"><i class="fa fa-tags" aria-hidden="true"></i><a class="text-info badge badge-pill bg-light" href="tag/tag_question.html"><small >Java基础 &nbsp;</small></a></div></div><div class="row"><div class="col-12 text-right"><div class="list-inline mb-1 "><small class="list-inline-item"v-text="question.nickname">风继续吹</small><small class="list-inline-item"><span v-text="question.pageViews">12</span>浏览</small><small class="list-inline-item" >13分钟前</small></div></div></div></div><!-- / class="media-body"--><img src="img/tags/example0.jpg"  class="ml-3 border img-fluid rounded" alt="" width="208" height="116"></div><div class="row mt-2"><div class="col-6 offset-3"><nav aria-label="Page navigation example"><div class="pagination"><a class="page-item page-link" href="#" >上一页</a><a class="page-item page-link " href="#" >1</a><a class="page-item page-link" href="#" >下一页</a></div></nav></div></div></div>

步骤2:

js/index.js文件修改为

/*
显示当前用户的问题*/
let questionsApp = new Vue({el:'#questionsApp',data: {questions:[]},methods: {loadQuestions:function () {$.ajax({url: '/v1/questions/my',method: "GET",success: function (r) {console.log("成功加载数据");console.log(r);if(r.code === OK){questionsApp.questions = r.data;}}});}},created:function () {console.log("执行了方法");this.loadQuestions(1);}
});

随笔

内存操作是纳秒级别

硬盘操作是毫秒级别

1毫秒=1000微妙

1微秒=1000纳秒

内存和硬盘操作差着百万倍级别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/25504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML5 Canvas(画布)

<canvas>标签定义图形&#xff0c;比如图表和其他图像&#xff0c;你必须用脚本来绘制图形。 在画布上&#xff08; Canvas &#xff09;画一个共红色矩形&#xff0c;渐变矩形&#xff0c;彩色矩形&#xff0c;和一些彩色文字。 什么是 Canvas&#xff1f; HTML5<c…

机器学习深度学习——序列模型(NLP启动!)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——卷积神经网络&#xff08;LeNet&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习&&深度…

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存二级缓存

Mybatis一级缓存&二级缓存 概述一级缓存特点演示前准备效果演示在同一个SqlSession中在不同的SqlSession中 源代码怎么禁止使用一级缓存一级缓存在什么情况下会被清除 二级缓存特点演示前准备效果演示在不同的SqlSession中 源代码怎么关闭二级缓存 一级缓存&#xff08;Spr…

Docker 安装 Tomcat

目录 一、查看 tomcat 版本 二、拉取 Tomcat Docker 镜像 三、创建 Tomcat 容器 四、访问 Tomcat 五、停止和启动容器 一、查看 tomcat 版本 访问 tomcat 镜像库地址&#xff1a;https://hub.docker.com/_/tomcat&#xff0c;可以通过 Tags 查看其他版本的 tomcat; 二、拉…

Android Studio 的Gradle版本修改

使用Android Studio构建项目时&#xff0c;需要配置Gradle&#xff0c;与Gradle插件。 Gradle是一个构建工具&#xff0c;用于管理和自动化Android项目的构建过程。它使用Groovy或Kotlin作为脚本语言&#xff0c;并提供了强大的配置能力来定义项目的依赖关系、编译选项、打包方…

HCIA---OSI/RM--开放式系统互联参考模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.OSI--开放式系统互联参考模型简介 OSI开放式系统互联参考模型是一种用于计算机网络通信…

解密Redis:应对面试中的缓存相关问题2

面试官&#xff1a;Redis集群有哪些方案&#xff0c;知道嘛&#xff1f; 候选人&#xff1a;嗯~~&#xff0c;在Redis中提供的集群方案总共有三种&#xff1a;主从复制、哨兵模式、Redis分片集群。 面试官&#xff1a;那你来介绍一下主从同步。 候选人&#xff1a;嗯&#xff…

Flutter iOS 集成使用 fluter boost

在 Flutter项目中集成完 flutter boost&#xff0c;并且已经使用了 flutter boost进行了路由管理&#xff0c;这时如果需要和iOS混合开发&#xff0c;这时就要到 原生端进行集成。 注意&#xff1a;之前建的项目必须是 Flutter module项目&#xff0c;并且原生项目和flutter m…

Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机接口数据吞吐量(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里函数来获取相机当前数据吞吐量&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在BGAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过BGAPI SDK获取数…

【微信小程序】van-uploader实现文件上传

使用van-uploader和wx.uploadFile实现文件上传&#xff0c;后端使用ThinkPHP。 1、前端代码 json&#xff1a;引入van-uploader {"usingComponents": {"van-uploader": "vant/weapp/uploader/index"} }wxml&#xff1a;deletedFile是删除文件函…

Xilinx FPGA电源设计与注意事项

1 引言 随着半导体和芯片技术的飞速发展&#xff0c;现在的FPGA集成了越来越多的可配置逻辑资源、各种各样的外部总线接口以及丰富的内部RAM资源&#xff0c;使其在国防、医疗、消费电子等领域得到了越来越广泛的应用。当采用FPGA进行设计电路时&#xff0c;大多数FPGA对上电的…

【计算机网络】12、frp 内网穿透

文章目录 一、服务端设置二、客户端设置 frp &#xff1a;A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet。是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且…

VUE框架:vue2转vue3全面细节总结(5)过渡动效

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

ES6 数组的用法

1. forEach() 用来循环遍历的 for 数组名.forEach(function (item,index,arr) {})item:数组每一项 , index : 数组索引 , arr:原数组作用: 用来遍历数组 let arr [1, 2, 3, 4]; console.log(arr); let arr1 arr.forEach((item, index, arr) > {console.log(item, index…

HTTP——八、确认访问用户身份的认证

HTTP 一、何为认证二、BASIC认证BASIC认证的认证步骤 三、DIGEST认证DIGEST认证的认证步骤 四、SSL客户端认证1、SSL 客户端认证的认证步骤2、SSL 客户端认证采用双因素认证3、SSL 客户端认证必要的费用 五、基于表单认证1、认证多半为基于表单认证2、Session 管理及 Cookie 应…

Android network — iptables四表五链

Android network — iptables四表五链 1. iptables简介2. iptables的四表五链2.1 iptables流程图2.2 四表2.3 五链2.4 iptables的常见情况 3. NAT工作原理3.1 BNAT3.2 NAPT 4. iptables配置 本文主要介绍了iptables的基本工作原理和四表五链等基本概念以及NAT的工作原理。 1. i…

RocketMQ Learning

一、RocketMQ RocketMQ的产品发展 MetaQ&#xff1a;2011年&#xff0c;阿里基于Kafka的设计使用Java完全重写并推出了MetaQ 1.0版本 。 2012年&#xff0c;阿里对MetaQ的存储进行了改进&#xff0c;推出MetaQ 2.0&#xff0c;同年阿里把Meta2.0从阿里内部开源出来&am…

杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)

文章目录 01 准备工作02 &#xff08;可选&#xff09;配置交换内存03 编辑docker-compose.yml04 启动并修改配置05 nginx反向代理06 &#xff08;可选&#xff09;修改配置文件07 访问并登录 01 准备工作 最近想自建一个gitlab服务来保存自己的项目&#xff0c;于是找到gitla…

使用XMLHttpRequest实现文件异步下载

1、问题描述 我想通过异步的方式实现下载文化&#xff0c;请求为post请求。一开始我打算用ajax。 $.ajax({type:post,contentType:application/json,url:http://xxx/downloadExcel,data:{data:JSON.stringify(<%oJsonResponse.JSONoutput()%>)},}).success(function(dat…

Linux远程连接mysql 出错plugin caching_sha2_password could not be loaded:

问题描述&#xff1a; 今天使用SQLyog远程连接mysql时出错plugin caching_sha2_password could not be loaded问题。 但在本地cmd 进入命令行窗口&#xff1a;输入命令连接远程连接mysql&#xff0c;发现可以顺利连接。 主要问题是 MySQL可视化工具&#xff08;如&#xff1a…