【开源项目--稻草】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;机器学习&&深度…

vue3+vite项目配置ESlint、pritter插件

配置ESlint、pritter插件 在 Vue 3 Vite 项目中&#xff0c;你可以通过以下步骤配置 ESLint 和 Prettier 插件&#xff1a; 安装插件&#xff1a; 在项目根目录下&#xff0c;打开终端并执行以下命令安装 ESLint 和 Prettier 插件&#xff1a; npm install eslint prettier e…

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

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

ubuntu20.4 sgx环境配置

一、driver安装 1.在该下载地址将3个.bin文件下载下来&#xff0c;下载地址&#xff1a;https://download.01.org/intel-sgx/latest/linux-latest/distro/ubuntu20.04-server/ 2.到下载文件夹下输入下面命令&#xff0c;以赋予.bin文件的执行权限 sudo chmod 777 sgx_linux_x64…

HTTP 常用状态码 301 302 304 403

HTTP 常用状态码 301 302 304 403 301 永久重定向&#xff0c;浏览器会把重定向后的地址缓存起来&#xff0c;将来用户再次访问原始地址时&#xff0c;直接引导用户访问新地址 302 临时重定向&#xff0c;浏览器会引导用户进入新地址&#xff0c;但不会缓存原始地址&#xff0c…

Python模块—Pytest模块

文章目录 PyTest1. args参数2. pytest-ordering3. fixture&#xff08;前置函数&#xff09;4. parametrize&#xff08;参数化&#xff09;5. fixture 与 parametrize 结合6. pyyaml&#xff08;数据源&#xff09;7. pytest-xdist&#xff08;分布式测试&#xff09;8. allur…

LA@行列式性质

文章目录 行列式性质&#x1f388;转置不变性质交换性质多重交换移动(抽出插入)&#x1f47a; 因子提取性质拆和性质倍加性质 手算行列式的主要方法原理:任何行列式都可以化为三角行列式 行列式性质&#x1f388; 设行列式 ∣ A ∣ d e t ( a i j ) |A|\mathrm{det}(a_{ij}) …

vue 关于axios的使用方法

axios定义&#xff1a; axios 前端 ajax请求工具 1. 在浏览器与nodejs可以使用 2. 可以拦截请求与相应 3. 扩展与封装自定义方法 4. 不依赖dom节点 安装 npm i axios -S 先在vue全局中挂载 import axios from ‘axios’ Vue.prototype.$h…

Docker 安装 Tomcat

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

Elasticsearch8.8.0 SpringBoot实战操作各种案例(索引操作、聚合、复杂查询、嵌套等)

Elasticsearch8.8.0 全网最新版教程 从入门到精通 通俗易懂 配置项目 引入依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency><dependency>&l…

Android Studio 的Gradle版本修改

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

Jtti:linux如何配置dns域名解析服务器

要配置Linux上的DNS域名解析服务器&#xff0c;您可以按照以下步骤进行操作&#xff1a; 1. 安装BIND软件包&#xff1a;BIND是Linux上最常用的DNS服务器软件&#xff0c;您可以使用以下命令安装它&#xff1a; sudo apt-get install bind9 2. 配置BIND&#xff1a;BIND的配置…

Spring Cloud常见问题处理和代码分析

目录 1. 问题&#xff1a;如何在 Spring Cloud 中实现服务注册和发现&#xff1f;2. 问题&#xff1a;如何在 Spring Cloud 中实现分布式配置&#xff1f;3. 问题&#xff1a;如何在 Spring Cloud 中实现服务间的调用&#xff1f;4. 问题&#xff1a;如何在 Spring Cloud 中实现…

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…

基于WebRTC升级的低延时直播

快直播-基于WebRTC升级的低延时直播-腾讯云开发者社区-腾讯云 标准WebRTC支持的音视频编码格式已经无法满足国内直播行业需求。标准WebRTC支持的视频编码格式是VP8/VP9和H.264&#xff0c;音频编码格式是Opus&#xff0c;而国内推流的音视频格式基本上是H.264/H.265AAC的形式。…

Flutter iOS 集成使用 fluter boost

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

离线数仓中,为什么用两个flume,一个kafka

实时数仓中&#xff0c;为什么没有零点漂移问题&#xff1f; 因为flink直接取的事件时间用kafka是为了速度快&#xff0c;并且数据不丢&#xff0c;那为什么既用了kafkachannel&#xff0c;也用了kafka&#xff0c;而不只用kafkachannel呢&#xff1f; 因为需要削峰填谷离线数仓…

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

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