springboot前端交互

一,Vue

1.vue基本使用

Vue.js 是什么

  1. Vue 是一套用于构建用户界面的渐进式 Javascript 框架; 2. 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用; 3. Vue 采用组件化模式,提高代码复用率、更好的代码维护; 4. 声明式编码,无需直接操作 DOM,提高开发效率; 5. 总而言之,vue就是一个MVVM的实现者,核心就是实现DOM监听和数据绑定

1,第一个Vue程序

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue引入</title>
<script src="../js/vue.js" type="text/javascript"></script>
<!-- 设置为 false 以阻止 vue 在启动时生成生产提示。 -->
<script>Vue.config.productionTip = false</script>
</head>
<body>
<div id="app">
{{message}}
</div>
<script type="text/javascript">
// 创建Vue的实例
const vm = new Vue({
// 绑定实例容器
el:"#app",
// 定义数据内容
data:{
message:"Hello Vue!"
}
})
</script>
</body>
</html>

其中

1. div 标签定义的内容就是 Vue 实例生效的容器;

2. el 用于绑定实例容器;

3. data 就是定义 Vue 实例数据的地方;

4. vm 绑定,当 data 数据发生改变时,页面内容也立刻发生改变;

5. 通过胡须表达式(插值语法) {{xxx}} 可以取出 Vue 实例中 data 属性中定义的 xxx 的值;

6. 双大括号会将数据解释为普通文本,而非 HTML 代码。

2,Vue指令

     指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达 式 ( v-for 是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

①v-bind指令

v-bind 是属性绑定指令,会把绑定的内容当做 js 表达式进行解析;

一般情况下,解析标签属性、解析标签体内容、绑定事件等,使用 v-bind 指令;

格式为: v-bind 缩写 :属性名="..."

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app" v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</div>
</body>
<script>
var app = new Vue({
el:'#app',
data:{
message:'页面加载于 ' + new Date().toLocaleString(), // 时间
}
})
</script>
</html>

②v-model指令

v-model 就是 Vue 中的数据绑定指令;

只能用于表单类元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值;

 v-model 指令其实就是 v-bind:value="属性值" + v-on:input="函数名"。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单双向数据绑定</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{message}}</p>
<input type="text" v-model="message">
</div>
<script>
var first = new Vue({
el:"#app",
data:{
message:"表单双向数据绑定"
}
})
</script>
</body>
</html>

③v-html指令

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>加载HTML代码</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app" v-html="message">
</div>
<script>
var first = new Vue({
el:"#app",
data:{
message:"<h1>Hello Vue!</h1>"
}
})
</script>
</body>
</html>

④v-show指令

v-show指令用来控制html元素是否显示

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>控制html元素显示</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p v-show="isTrue">{{message}}</p>
<input type="text" v-model="message">
<button v-on:click="change">点击我改变</button>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
message : "控制html元素显示",
isTrue : true,
},
methods:{
change:function () {
this.isTrue = !this.isTrue;
}
}
})
</script>
</body>
</html>

3.事件处理和流程控制

①v-on指令

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue模板语法</title>
<script src="../js/vue.js" type="text/javascript"></script>
<!-- 设置为 false 以阻止 vue 在启动时生成生产提示。 -->
<script>Vue.config.productionTip = false</script>
</head>
<body>
<div id="app">
<p>{{number}}</p>
<button v-on:click="add">增加</button>
<button v-on:click="add2($event,1)">增加2</button>
</div>
<script>
var first = new Vue({
el: "#app",
data: {
number: 1,
},
methods: {
add: function () {
console.log(event)
this.number += 1;
},
add2: function (event, num) {
console.log(event)
this.number += 1;
}
}
})
</script>
</body>
</html>

其中

方法定义在 Vue 实例的 methods 属性中;

方法调用时,如果没有参数传递,则直接写方法名即可,此时会默认传递当前事件 event 过去; 如果有参数传递,则需要写方法名和圆括号,此时 event 事件就会丢失,可以在参数传递的时候使 用 $event 进行占位;

在方法中,如果想要使用 Vue 实例中的 data 属性数据,使用 this.xxx 的方式,这个 this 就代表了 当前 Vue 的实例对象;

②文档事件

如果函数需要在文档加载完后执行,需要定义 mouted 属性或者 created 属性

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>文档事件</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{number}}</p>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
number : "文档事件",
},
methods:{
documentEven:function (data) {
alert(data);
}
},
mounted:function () {
this.documentEven("文档加载后执行");
}
})
</script>
</body>
</html>

③条件语句

Vue中的条件判断使用 v-if v-else-if v-else指令;

and 表示与,or 表示或。

<meta charset="UTF-8">
<title>文档事件</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{number}}</p>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
number : "文档事件",
},
methods:{
documentEven:function (data) {
alert(data);
}
},
mounted:function () {
this.documentEven("文档加载后执行");
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>条件指令</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p v-if="weekday == '星期一'">
今天是星期一
</p>
<p v-else-if="weekday == '星期二'">
今天是星期二
</p>
<p v-else-if="weekday == '星期三'">
今天是星期三
</p>
<p v-else-if="weekday == '星期四'">
今天是星期四
</p>
<p v-else-if="weekday == '星期五'">
今天是星期五
</p>
<p v-else>
今天是周末
</p>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
weekday:"星期五"
}
})
</script>
</body>
</html>

④循环语句

1. Vue中循环语句使用v-for指令,v-for 指令是以 x in sites 形式的特殊语法, sites 是源数据数组,x 是数组元素迭代的别名;

2. 如果需要循环的下标,可以写成(x,index) in sites,index从0开始;

3. 一共可以有三个参数,value、name、index,分别对应值、键、索引。

<p v-else-if="weekday == '星期四'">
今天是星期四
</p>
<p v-else-if="weekday == '星期五'">
今天是星期五
</p>
<p v-else>
今天是周末
</p>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
weekday:"星期五"
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>循环指令</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<table border="1" cellspacing="0">
<thead>
<tr>
<td>id</td>
<td>username</td>
<td>password</td>
</tr>
</thead>
<tbody>
<tr v-for="(user,index) in userList">
<td>{{index + 1}}</td>
<td>{{user.username}}</td>
<td>{{user.password}}</td>
</tr>
</tbody>
</table>
</div>
<script>
var first = new Vue({
el:"#app",
data:{
userList:[
{username:"张三",password:"123"},
{username:"李四",password:"111"},
{username:"王五",password:"222"},
{username:"赵六",password:"333"},
]
}
})
</script>
</body>
</html>

4.Vue表单

①输入框

直接使用input框和textarea框

②复选框

复选框也是使用 v-model 实现双向数据绑定,需要注意的是定义的值是一个js数组

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>复选框</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>复选框:</p>
<label for="movie">电影</label>
<input type="checkbox" id="movie" value="电影" v-model="checkedNames">
<label for="game">游戏</label>
<input type="checkbox" id="game" value="游戏" v-model="checkedNames">
<label for="book">看书</label>
<input type="checkbox" id="book" value="看书" v-model="checkedNames">
<br>
<span>选择的值为:{{checkedNames}}</span>
</div>
<script>
var first = new Vue({
el: '#app',
data: {
checkedNames: [],
}
})
</script>
</body>
</html>

③单选框

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>单选框</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>单选框:</p>
<label for="man">男</label>
<input type="radio" id="man" value="男" v-model="sex">
<br>
<label for="woman" >女</label>
<input type="radio" id="woman" value="女" v-model="sex">
<br>
<span>选中值为:{{sex}}</span>
</div>
<script>
var first = new Vue({
el: '#app',
data: {
sex: '',
}
})
</script>
</body>
</html>

④下拉框

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>下拉框</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>下拉框:</p>
<select v-model="url" >
<option value="">选择一个网站</option>
<option value="www.baidu.com">百度</option>
<option value="www.google.com">谷歌</option>
</select>    
<br/>
<span>选中值为:{{url}}</span>
</div>
<script>
var first = new Vue({
el: '#app',
data: {
url: '',
}
})
</script>
</body>
</html>

二,Thymeleaf

   Thymeleaf 是新一代 Java 模板引擎,与 Velocity、FreeMarker 等传统 Java 模板引擎不同,Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,因此它可以直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板的静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。

简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下两个个极吸引人的特点:

  1. 它支持 html 原型

  2. Jsp中EL表达式和JSTL标签能完成工作,它都几乎都能完成

1. 环境搭建

在pom.xml导入依赖

<!--Thymeleaf 启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在application.yml文件中添加配置

spring:
  thymeleaf:
  	#文件存放路径前缀
    prefix: classpath:/templates/
    encoding: UTF-8
    #文件类型
    mode: html
    cache: false

 

在resources下创建templates 目录,用于存放.html文件

2.Thymeleaf 变量表达式

Thymeleaf 作为一种模板引擎,它拥有自己的语法规则,常用的变量表达式

属性描述实例
th:text文本替换,转义特殊字符<span th:text="${info}"></span>
th:value替换 value 属性<input th:value = "${user.name}" />
th:each遍历,支持 Iterable、Map、数组等<table> <tr th:each="m:${session.map}"> <td th:text="${m.getKey()}"></td> <td th:text="${m.getValue()}"></td> </tr> </table>
th:if根据条件判断是否需要展示此标签<a th:if ="${userId == collect.userId}">
th:selectedselect 选择框选中<select> <option>---</option> <option th:selected="${name=='a'}"> 成都 </option> <option th:selected="${name=='b'}"> 北京</option>** </select>

3.案例

使用Thymeleaf手动实现表格分页

前后端不分离

controller层

package com.hqyj.j220701.springboot.springbootdemo01.user.controller;

import com.hqyj.j220701.springboot.springbootdemo01.user.dto.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Controller
@RequestMapping("/api/user")
public class UserController {

    @RequestMapping("/list")
    public String getUserListView(Integer pageNumber, Model model){
        if (Objects.isNull(pageNumber)){
            pageNumber = 0;
        }

      /*  if (null == pageNumber){
            pageNumber = 0;
        }*/

        List<UserInfo> userInfoList = new ArrayList<>();
        for (int i = 0; i < 10 ; i++) {
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setUserName("zhangsan" + i);
            userInfo1.setPassword("123456");
            userInfo1.setSex("m");
            userInfo1.setAge(20);
            userInfoList.add(userInfo1);
        }

        //分页的设计
        int pageSize = 2;//页面大小
        int total = userInfoList.size();//总记录数
        int totalPage = total / pageSize;//一共多少页
        //如果取模有余数,表示还有数据未被分页,total加一
        if (total % pageSize != 0){
            totalPage++;
        }
        //当前页
        int fromIndex = (pageNumber * pageSize);//开始下标
        int toIndex = fromIndex + pageSize;//当前页结束下标
        //防止下标越界
        if (toIndex >= total){
            toIndex = total;
        }
        //区间:[fromIndex,toIndex)
        List<UserInfo> subList = userInfoList.subList(fromIndex, toIndex);

        model.addAttribute("list",subList);
        model.addAttribute("pageNumber",pageNumber);
        model.addAttribute("totalPage",totalPage);
        return "user_list";
    }
}

在dto层创建用户信息类UserInfo

package com.hqyj.j220701.springboot.springbootdemo01.user.dto;

import lombok.Data;

@Data
public class UserInfo {
    private String userName;
    private String password;
    private String sex;
    private Integer age;
}

html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row">
        <div>
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>姓名</th>
                    <th>密码</th>
                    <th>性别</th>
                    <th>年龄</th>
                </tr>
                </thead>
                <tbody>
                <tr th:each="user:${list}">
                    <td th:text="${user.userName}"></td>
                    <td th:text="${user.password}"></td>
                    <td th:text="${user.sex}"></td>
                    <td th:text="${user.age}"></td>

                </tr>
                </tbody>
            </table>
        </div>
    </div>
    <div class="row">
        <div class="modal-footer">
            <ul class="pagination pull-right">
                <li><a th:href="@{/api/user/list(pageNumber=0)}">首页</a></li>
                <li th:if="${pageNumber} > 0">
                    <a th:href="@{/api/user/list(pageNumber= ${pageNumber} - 1)}">前一页</a>
                </li>
                <li th:if="${pageNumber} < ${totalPage} - 1">
                    <a th:href="@{/api/user/list(pageNumber= ${pageNumber} + 1)}">后一页</a>
                </li>
                <li><a th:href="@{/api/user/list(pageNumber=${totalPage} - 1)}">尾页</a></li>
            </ul>
        </div>
    </div>
</div>
</body>
</html>

前后端分离

后端代码相同,前端代码在Hbuilder编写

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="js/jquery-3.6.0.min.js"></script>
		<link href="css/bootstrap.min.css" rel="stylesheet" />
		<script src="js/vue.js"></script>
	</head>
	<body>
		<div class="container" id="app">
			<div class="row">
				<div>
					<table class="table table-bordered">
						<thead>
							<tr>
								<th>序号</th>
								<th>姓名</th>
								<th>密码</th>
								<th>性别</th>
								<th>年龄</th>
							</tr>
						</thead>
						<tbody>
							<tr v-for="(user,index) in userList">
								<td>{{index + 1}}</td>
								<td>{{user.userName}}</td>
								<td>{{user.password}}</td>
								<td>{{user.sex}}</td>
								<td>{{user.age}}</td>
							</tr>
						</tbody>
					</table>
				</div>
			</div>
			<div class="row">
				<div class="modal-footer">
					<ul class="pagination pull-right">
						<li>
							<a href="javascript:void(0);" v-on:click="firstPage()">首页</a>
						</li>
						<li v-if="pageNumber>0">
							<a href="javascript:void(0);" @click="prePage()">上一页</a>
						</li>
						<li v-if="pageNumber<totalPage-1">
							<a href="javascript:void(0);" @click="nextPage()">下一页</a>
						</li>
						<li>
							<a href="javascript:void(0);" v-on:click="lastPage()">尾页</a>
						</li>
					</ul>
				</div>
			</div>
		</div>

		<script>
			var vm = new Vue({
				el: "#app",
				data: {
					userList: [],
					pageNumber: 0,
					totalPage: 0,
					total: 0
				},
				methods: {
					getUserList: function() {
						var _this = this;
						var params = {
							pageNumber: this.pageNumber
						};
						$.ajax({
							url: "http://localhost:8082/api/user/list",
							type: "GET",
							dataType: "json",
							data: params,
							success: function(data) {
								if (data.code == 200) {
									_this.userList = data.userList;
									_this.pageNumber = data.pageNumber;
									_this.totalPage = data.totalPage;
									_this.total = data.total;
								} else {
									alert("接口调用失败");
								}
							},
							error: function() {
								alert("请求失败");
							}
						});
					},
					firstPage: function() {
						this.pageNumber = 0;
						this.getUserList();
					},
					prePage: function() {
						this.pageNumber--;
						this.getUserList();
					},
					nextPage: function() {
						this.pageNumber++;
						this.getUserList();
					},
					lastPage: function() {
						this.pageNumber = this.totalPage - 1;
						this.getUserList();
					}
				},
				mounted: function() {
					this.getUserList();
				}
			})
		</script>
	</body>
</html>

前后端分离时会遇到一个问题:跨域问题

前后端代码完成后进行调试,当前端页面访问后台接口时会出现跨域问题。

跨域问题的根本原因:浏览器有同源策略限制,当前域名的js只能读取同域下的窗口属性,这是一个基础安全功能。那么什么是同源策略呢?即两资源的URL中 协议域名端口,都相同则称为同源,若两资源为不同源,则不允许共享资源。例如:后台接口域名为百度一下,你就知道,前端发送请求情况如下:

请求地址结果原因
http://www.baidu.com/dir1/b.html成功同一域名端口,相同文件夹
http://www.baidu.com/dir2/a.html成功同一域名端口,不同文件夹
https://www.baidu.com/dir1/b.html失败不同协议,http与https
http://www.baidu.com:8000/dir1/b.html失败不同端口,默认为80
新浪网失败不同域名

复杂的跨域请求,浏览器会先发送一个OPTIONS探路,收到响应允许跨域后会再发送真实请求。此时服务端写代码时,还需响应(OPTIONS)允许跨域。

后台解决跨域问题:

创建CorsWebFilter

@Configuration
public class CorsWebConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    }
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cqq00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值