javaweb尚硅谷版 一、 前端 1.Ajax 1.1 whay ajax? AJAX = Asynchronous JavaScript and XML(异步的 JavaScript和XML)。 AJAX不是新的编程语言,而是一种使用现有标准的新方法。 AJAX最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。 AJAX不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。 XMLHttpRequest只是实现Ajax的一种方式。 工作原理 :
·简单来说,我们之前发的请求通过类似form表单标签,a标签这种方式,现在通过运行js代码动态决定什么时候发送什么样的请求。 通过运行Js代码发送的请求浏览器可以不用跳转页面,我们可以在JS代码中决定是否要跳转页面 ·通过运行JS代码发送的请求,接收到返回结果后,我们可以将结果通过dom编程渲染到页面的某些元素上,实现局部更新 1.2 使用说明 html
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > <script > function getMessage ( ){ var xmlhttp = new XMLHttpRequest (); xmlhttp.onreadystatechange = function ( ) { if (xmlhttp.readyState == 4 && xmlhttp.status == 200 ) { console .log (xmlhttp.responseText ); var inputEle= document .getElementById ("message" ); inputEle.value =xmlhttp.responseText ; } } xmlhttp.open ("GET" , "/hello?username=zhangsan" , true ); xmlhttp.send (); } </script > </head > <body > <button onclick ="getMessage()" > 在吗</button > <input type ="text" id ="message" > </body > </html >
java
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/hello") public class HelloServlet extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8" ); resp.setContentType("text/html;charset=UTF-8" ); String username = req.getParameter("username" ); resp.getWriter().write("hello " + username); } }
2.前端工程化 前端工程化是使用软件工程的方法来单独解决前端的开发流程中模块化、组件化、规范化、自动化
的问题,其主要目的为了提高效率和降低或本。
3.es6 3.1 es6的变量和模板字符串 let不能重复声明 let有块级作用域,非函数的花括号遇见let会有块级作用域,也就是只能在花括号里面访问。 let不会预解析进行变量提升 let定义的全局变量不会作为window的属性 let在es6中推荐优先使用 <script> var i=10 let j=10 let j=100 { var i=10 let j=10 console .log (j) } console .log (i) console .log (i) var i=10 console .log (j) var j=10 var a =10 let b =10 console .log (window .a ) console .log (window .b ) const let c=10 let city ='背景' let str = `<ul> <li></li> <li>${city} </li> <li></li> </ul>` ; </script>
3.2 es6的解构表达式 ES6的解构赋值是一种方便的语法,可以快速将数组或对象中的值拆分并赋值给变量。解构赋值的语法使用花括号{}
表示对象,方括号[]
表示数组。通过解构赋值,函数更方便进行参数接受等!
数组解构赋值
let [a,b,c]=[1 ,2 ,3 ] console .log (a); console .log (b); console .log (c);
该语句将数组[1,2,3]中的第一个值赋值给a变量,第二个值赋值给b变量,第三个值赋值给c变量。可以使用默认值为变量提供备选值,在数组中缺失对应位置的值时使用该默认值。例如: let [a,b,c,d,e=10 ]=arrconsole .log (a,b,c,d,e)let person={ name :"zhangsan" , age :10 }
对象解构赋值
let person={ name :"zhangsan" , age :10 } let {age,name}=personconsole .log (age,name)
let arr =[11 ,22 ,33 ,44 ,55 ] function showArr ([a,b,c] ){ console .log (a,b,c) } showArr (arr)
3.3 es6的箭头函数 基本功能
let fun1 =function ( ){} let fun2 =( ) =>{} let fun3 =(x )=>{return x+1 } let fun4 =x=>{return x+1 } let fun5 =(x )=>console .log (x) let fun6 =(x )=> x+1
this
箭头函数没有自己的this
箭头函数中的this是外层上下文环境中的this
let person ={ name :'张三' , showName :function ( ){ console .log (this .name ) }, viewName :()=> { console .log (this .name ) } } person.showName () person.viewName ()
案例 :
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > #xdd { display : inline-block; width : 200px ; height : 200px ; background-color : red; } </style > </head > <body > <div id ="xdd" > </div > <script > var xdd=document .getElementById ("xdd" ) xdd.onclick =function ( ){ window .setTimeout (()=> { this .style .backgroundColor ="yellow" },2000 ) } </script > </body > </html >
3.4 rest和spread rest参数,在形参上使用和JAVA中的可变参数几乎一样
spread参数,在实参上使用rest
<script> let fun1 =(a,b,c,...arr )=>{ console .log (a,b,c) console .log (arr) } fun1 (1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ) let arr=[1 ,2 ,3 ] let fun2 =(a,b,c )=>{ console .log (a,b,c) } fun1 (...arr) let a =[1 ,2 ,3 ] let b =[1 ,2 ,3 ] let c =[1 ,2 ,3 ] let d=[...a,...b,...c] let person1={name :"李阳" } let person2={age :"10" } let person3={gender :"boy" } let person4={...person1,...person2,...person3} </script>
3.5 es6的对象创建和拷贝 对象创建 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script > class Person { #n; age; get name () { return this .#n; } set name (n ) { this .#n = n; } eat (food ){ console .log (`${this .age} 岁的${this .#n} 正在吃${food} ` ) } static sum (a,b ){ return a+b } constructor (name,age ){ this .#n=name; this .age =age; } } </script > </head > <body > </body > </html >
3.6 es6模块化处理 模块化是一种组织和管理前端代码的方式,将代码拆分成小的模块单元,使得代码更易于维护、扩展和复用。它包括了定义、导出、导入以及管理模块的方法和规范。前端模块化的主要优势如下:
提高代码可维护性:通过将代码拆分为小的模块单元,使得代码结构更为清晰,可读性更高,便于开发者阅读和维护。 提高代码可复用性:通过将重复使用的代码变成可复用的模块,减少代码重复率,降低开发成本。 提高代码可扩展性:通过模块化来实现代码的松耦合,便于更改和替换模块,从而方便地扩展功能。 ES6模块化的几种暴露和导入方式分别导出 统一导出 默认导出 ES6中无论以何种方式导出,导出的都是一个对象,导出的内容都可以理解为是向这个对象中添和属性或者方法
分别导出 需要添加export关键字
model.js
export const PI =3.14 const PI2 =3.1415926 function sum (a,b ){ return a+b } class Person { constructor (name,age ){ this .name =name; this .age =age; } sayHello ( ){ console .log (`hello,my name is ${this .name} ,I am ${this .age} years old` ) } }
app.js
import * as m1 from './module.js' console .log (m1.PI ) console .log (m1.PI2 )
index.html
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script src ="./app.js" type ="module" > </script > </head > <body > </body > </html >
4.VUE 4.1 vite创建前端工程化页面 vs的控制台中输入 npm create vite即可 cd 到我们创建的目录 运行npm i 运行npm run dev
public目录:用于存放一些公共资源,如HTML文件、图像、字体等,这些资源会被直接复制到构建出的目标目录中。 src/目录:存放项目的源代码,包括JavaScript、CSs、Vue组件、图像和字体等资源。在开发过程中,这些文件会被Vite 实时编译和处理,并在浏览器中进行实时预览和调试。以下是src内部划分建议:assets/
目录:用于存放一些项目中用到的静态资源,如图片、字体、样式文件等。components/
目录:用于存放组件相关的文件。组件是代码复用的一种方式,用于抽象出一个可复用的U部件,方便在不同的场景中 进行重复使用。layouts/
目录:用于存放布局组件的文件。布局组件通常负责整个应用程序的整体布局,如头部、底部、导航菜单等。pages/
目录:用于存放页面级别的组件文件,通常是路由对应的组件文件。在这个目录下,可以创建对应的文件夹,用于存储不同的 页面组件。plugins/
目录:用于存放vte 插件相关的文件,可以按需加载不同的插件来实现不同的功能,如自动化测试、代码压缩等。routerl
目录:用于存放Wwejis的路由配置文件,负责管理视图和URL之间的映射关系,方便实现页面之间的跳转和数据传递。store/
目录:用于存放Vuex状态管理相关的文件,负责管理应用程序中的数据和状态,方便统一管理和共享数据,提高开发效率。utils/
目录:用于存放一些通用的工具函数,如日期处理函数、字符串操作函数等。 vite.config js文件: Vite的配置文件,可以通过该文件配置项目的参数、插件、打包优化等。该文件可以使用CommonS或ES6模块的语法进行配置。 package.json文件:标准的 Node.is项目配置文件,包含了项目的基本信息和依赖关系。其中可以通过scripts字段定义几个命令,如dev.build、serve等,用于启动开发、构建和启动本地服务器等操作。 Vie项点的入口为src/main,js文件,这是’Vue,js 应用程序的启动文件,也是整个前端应用程序的入口文件。在该文件中,通常会引入Mue.js及其相关插件和组件,同时会创建Vue实例,挂载到HTML页面上指定的DOM元素中。 4.2关于css样式引用的导入方式 <script setup> /*css样式引用的方式 1.在.vue文件中的style标签中 2.将css样式保存在独立的css文件中,哪个vue文件需要,就在那里导入 在script中导入 import'./style/test.css' 在style中导入 @import'./style/test.css' 3.如果某个样式要在所有vue中显示 可以在main中导入 import './style/test.css' */ import'./style/test.css' </script> <template> <div> <span class="s1">你好</span> </div> </template> <style scoped> @import'./style/test.css' </style>
4.3 vite+vue3响应式入门和setup函数 <script setup> import {ref} from 'vue' //定义一些要展示到页面上的数据 变量/对象 let counter =ref(2) //自增的方法 function counterIncr(){ counter.value++ } //自减的方法 function counterDecr(){ counter.value-- } /* 响应式数据:在数据变化时,vue会将变量最新的值更新到dom树中,页面上的数据就是最新的 非响应式数据:在数据变化时,vue不会更新 vue3中要经过ref/reactive函数处理才变成最新的 */ </script> <template> <div> <button @click="counterIncr()">+</button> <span v-text="counter"></span> <button @click="counterDecr()">-</button> </div> </template> <style scoped> </style>
5.vue的视图渲染技术 5.1插值表达式 <script setup> /* 插值表达式 {{数据名字/函数}} */ //定义常见类型的数据 let msg ="hello liyang" let getMsg=()=>{ return "hello vue3" } let age=11 let bee="蜜 蜂" let carts=[{name:"可乐",price:3,number:5},{name:"雪碧",price:4,number:5},{name:"辣条",price:0.5,number:5}] //定义一个获取购物车总金额的方法 function computer(){ let count=0 for(let index in carts){ count+=carts[index].price* carts[index].number } return count } </script> <template> <div> <!-- 将数据绑定到下面的元素 --> <h1>{{ msg }}</h1> msg的值为{{ msg }} msg的方法值为{{ getMsg() }}<br> <!-- 插值表达式支持一些常见的运算符 --> 年龄:{{ age }},是否成年{{ age>18?'是':'否' }}<br> <!-- 插值表达式中支持对象调用api --> {{ bee.split(' ').reverse().join('') }} <br> {{ computer() }} </div> </template> <style scoped> </style>
5.2 v-text与v-html <script setup> let msg="helloworld" let msg2="liyang" let msg3=`${msg} ${msg2}` let age = 19 let fontMsg="<font color='red'>你好</font>" </script> <template> <div> <h1>{{ msg }}</h1><br> <h1 v-text="msg3" ></h1> <h1 v-text="`你好 ${msg2}`" ></h1> <h1 v-text="age>18?'成年':'未成年'" ></h1> <h1 v-html="fontMsg" ></h1> </div> </template> <style scoped> </style>
5.3 Atteibute属性渲染 v-band <script setup> /* 属性渲染命令 v-bind 将数据绑定在元素属性上 */ //let imgURL="https://img.lwxpz.me/file/1739857121688_屏幕截图 2024-12-17 112612.png" const data={ logo:"https://img.lwxpz.me/file/1739857121688_屏幕截图 2024-12-17 112612.png", name:"liyang", url:"http://ly.baskly.us.kg" } </script> <template> <div> <!-- <img v-bind:src="imgURL"> --> <a v-bind:href="data.url"> <img v-bind:src="data.logo" v-bind:title="data.name"> </a> </div> </template> <style scoped> </style>
5.4 v-on 事件绑定 <script setup> import { ref } from 'vue'; /* v-on:事件名称="函数名()" 可以简写为@事件名称 */ function fun1() { alert("hi"); } let counter = ref(1); function fun3(event) { if (confirm("确定要访问目标链接吗")) { // 通过返回值控制是否阻止默认行为 event.preventDefault(); } } function fun4() { alert("被点击"); } </script> <template> <div> <!-- 事件的绑定函数 --> <button @click="fun1()">hello</button> <!-- 内联事件处理器 --> <button @click="counter++">+</button> <!-- 事件的修饰符 .once 事件只绑定一次 prevent修饰符阻止组件默认行为--> <button @click.once="counter++">Click Once</button> <a href="http://ly.baskly.us.kg" @click="fun3($event)">yang</a> <a href="http://ly.baskly.us.kg" @click.prevent="fun4()">yu</a> {{ counter }} </div> </template> <style scoped> </style>
5.5 响应式数据处理的方式 让一个普通数据转换为响应式数据的两种方式 1 ref函数 更适合单个变量 在script标签中操作ref响应式数据需要.value 在template标签中不需要.values 2 reactive函数 更适合对象
<script setup> import {ref,reactive} from 'vue' /* 让一个普通数据转换为响应式数据的两种方式 1 ref函数 更适合单个变量 在script标签中操作ref响应式数据需要.value 在template标签中不需要.values 2 reactive函数 更适合对象 */ let counter =ref(10) let person=reactive({ name:"李阳", age:8 }) function incr(){ counter.value++ } function incrAge(){ person.age++ } </script> <template> <div> <button @click="incr()">+</button> <button @click="counter++">+</button> {{ counter }} <hr> <button @click="incrAge()">+</button> {{ person.age }} </div> </template> <style scoped> </style>
5.6 条件和列表渲染 v-if/v-show和v-for v-if/v-show . v-if是“真实的“按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。 . v-if 也是惰性的:如果在初次渲染时条件值为false,则不会做任何事。条件区块只有当条件首次变为true时才被渲染。·相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有CSS display属性会被切换。 ·总的来说, v-if有更高的切换开销,而”v-show有更高的初始渲染开销。因此,如果需要频繁切换,则使用v-show较好;如果在运行时绑定条件很少改变,则v-if 会更合适。 <script setup> import{ref} from 'vue' /* v-if="表达式/数据" 数据为true 则当前元素会渲染进入dom树 v-else 自动和前一个v-if取反 v-show ="" 数据为true则展示到页面上 否则不展示 v-if 如果数据为false则元素不再dom树中了 v-show */ let flag=ref(true) </script> <template> <div> <h1 v-if="flag">vue is awesome!</h1> <h1 id="bb" v-else>ononon</h1> <h1 v-show="flag">hhh</h1> <button @click="flag=!flag">toggle</button> </div> </template> <style scoped> </style>
v-for <script setup> import {ref, reactive } from "vue"; let pro =ref("产品") let items = reactive([ { id: "item1", message: "薯片" }, { id: "item2", message: "面包" }, { id: "item3", message: "烤鸡" } ]); </script> <template> <div> <ul> <li v-for="item in items" :key="item.id"> {{ pro }} {{ item.message }} </li> </ul> </div> </template> <style scoped> </style>
小德莫demo <script setup> import { ref, reactive } from "vue"; let pro = ref("产品"); let items = reactive([ { id: "item1", message: "薯片" }, { id: "item2", message: "面包" }, { id: "item3", message: "烤鸡" } ]); let carts = reactive([ { name: "可乐", price: 3, number: 10 }, { name: "雪碧", price: 3, number: 1 }, { name: "薯片", price: 5, number: 20 }, { name: "辣条", price: 2, number: 5 } ]); function removeItem(index) { const confirmDelete = confirm("确定要删除该商品吗?"); if (confirmDelete) { carts.splice(index, 1); // 删除指定索引的商品 } } //计算总金额的函数 function compute(){ let total=0 for(let index in carts){ total+= carts[index].price*carts[index].number } return total } </script> <template> <div> <h1>您的购物车如下</h1> <table border="1px" class="cart-table"> <thead> <tr> <th>序号</th> <th>名称</th> <th>价格</th> <th>数量</th> <th>小计</th> <th>操作</th> </tr> </thead> <tbody> <tr v-for="(cart, index) in carts" :key="index"> <td>{{ index + 1 }}</td> <td>{{ cart.name }}</td> <td>{{ cart.price.toFixed(2) }}</td> <!-- 格式化价格 --> <td>{{ cart.number }}</td> <td>{{ (cart.price * cart.number).toFixed(2) }}</td> <!-- 格式化小计 --> <td> <button @click="removeItem(index)">删除</button> </td> </tr> </tbody> </table> 购物车总金额:{{ compute() }}元 <hr> <ul> <li v-for="item in items" :key="item.id"> {{ pro }} {{ item.message }} </li> </ul> </div> </template> <style scoped> .cart-table { width: 100%; border-collapse: collapse; } .cart-table th, .cart-table td { padding: 8px; text-align: center; } button { background-color: red; color: white; border: none; padding: 5px 10px; cursor: pointer; } button:hover { background-color: darkred; } hr { margin: 20px 0; } </style>
5.7 双向绑定 单项绑定 <script setup> import {ref} from 'vue' /* 单项绑定 响应式数据发生变化时,更新dom树 用户的操作如果造成页面内容的改变不会影响响应式数据 */ let message =ref("zhangsan") </script> <template> <div> <input type="text" v-bind:value="message"><br> {{ message }} </div> </template> <style scoped> </style>
双向绑定 <script setup> import { ref, reactive } from 'vue' /* 单项绑定 v-bind 响应式数据发生变化时,更新dom树 用户的操作如果造成页面内容的改变不会影响响应式数据 双向绑定 v-model 页面数据由于用户的操作造成改变,也会同步修改响应式数据 双向绑定一边都用于表单标签 v-model:value="数据" */ let user = reactive({ username: "", userPwd: "", intro:"", pro:"" }) let hbs=ref([]) function cleanForm(){ user.username="" user.userPwd="" user.intro="" user.pro="" hbs.value.splice(0,hbs.value.length) } </script> <template> <div> <input type="text" v-model="user.username"><br> <input type="password" v-model="user.userPwd"><br> 爱好: 唱<input type="checkbox" v-model="hbs" value="sing"> 跳<input type="checkbox" v-model="hbs" value="dance"> rap<input type="checkbox" v-model="hbs" value="rap"> 篮球<input type="checkbox" v-model="hbs" value="basketball"> 简介:<textarea v-model="user.intro"></textarea> <br> 籍贯: <select v-model="user.pro"> <option value="1">北京</option> <option value="2">河南</option> <option value="3">湖北</option> </select> <button @click="cleanForm">清空</button> <p>{{ user }}</p> {{ hbs }} </div> </template> <style scoped> </style>
5.8 属性计算 <script setup> import { reactive,computed } from 'vue'; /* 计算属性:其能不间断的执行这个箭头函数 让其数据保持最新,而原身的做不到 */ const author=reactive({ name:"李阳", books:["java从入门到精通"] }) //通过方法返回数据 每使用一次,执行一次 function hasBook(){ return author.books.length>0?"是":"否" } //通过计算属性获取数据 每次使用如果和上次使用的数据未发生变化,则使用上次数据 let bookMessage = computed(()=>{ return author.books.length>0?"是":"否" }) </script> <template> <div> <p>作者:{{ author.name }}</p> 是否出版过图书:{{ hasBook() }}<br> 是否出版过图书:{{ bookMessage }} </div> </template> <style scoped> </style>
5.9 数据监听 双向绑定版
<script setup> import { ref } from 'vue' let funame = ref('') let finame = ref('') </script> <template> <div> 姓氏: <input type="text" v-model="funame"><br> 名字: <input type="text" v-model="finame"><br> 全名: {{ funame }} {{ finame }} </div> </template> <style scoped> </style>
监听版
<script setup> import { ref, reactive, watch,watchEffect } from 'vue' let funame = ref('') let finame = ref('') let lastname = reactive({ name: "" }) //任何的响应式数据 ,如果是想监听,直接监听即可,无需将要监听的响应式数据作为参数 // watchEffect(()=>{ funame.value=finame.value+lastname.value }) // watch 函数监听 一个ref响应式数据 // 当 finame 发生变化时执行后面的函数 watch(finame, (newValue, oldValue) => { console.log(`${oldValue} 变为 ${newValue}`) // 更新 funame 为姓氏 + 名字 funame.value = newValue + lastname.name }) // watch 函数监听一个reactive响应式数据 专门监听reactive响应式数据中的一个属性 watch(() => lastname.name, (newValue, oldValue) => { console.log(`${oldValue} 变为 ${newValue}`) funame.value=finame.value+newValue }) //watch 函数监听一个reactive响应式数据 专门监听reactive响应式数据中的所有属性 watch(() => lastname, (newValue, oldValue) => { //此时new和old都一样,都是last funame.value=finame.value+lastname.name },{deep:true,immediate:true})//是否要深度监听(监听所有属性),是否要先监听一次 </script> <template> <div> 姓氏: <input type="text" v-model="funame"><br> 名字: <input type="text" v-model="finame"><br> <br> <input type="text" v-model="lastname.name" placeholder="请输入姓氏"><br> 全名: {{ funame }} </div> </template> <style scoped> </style>
5.10 组件化 白雪警告
Header.vue
<script setup> </script> <template> <div> <h5>欢迎:xxx的光临<a href="#">退出登录</a> </h5> </div> </template> <style scoped> </style>
Navigator.vue
<script setup> //向父组件发送参数 import {defineEmits} from 'vue' //定义一个向父组件提交数据的事件 事件名称自定义 const emits= defineEmits(["sendMenu"]) //提交数据的方法 function send(data) { emits("sendMenu",data) } </script> <template> <div> <ul> <li @click="send('学员管理')">学员管理</li> <li @click="send('图书管理')">图书管理</li> <li @click="send('请假管理')">请假管理</li> <li @click="send('班级管理')">班级管理</li> <li @click="send('教师管理')">教师管理</li> <li @click="send('考试管理')">考试管理</li> </ul> </div> </template> <style scoped> </style>
Content.vue
<script setup> //接收父组件的参数 import {defineProps} from 'vue' defineProps({ message:String }) </script> <template> <div> 这里是展示区 {{ message }} </div> </template> <style scoped> </style>
App.vue
<script setup> import {ref} from 'vue' //引用3个组件 import Header from './components/Header.vue' import Navigator from './components/Navigator.vue'; import Content from './components/Content.vue'; let menu =ref("") function receiver(data){ menu.value=data } </script> <template> <div> <Header class="header"></Header> <Navigator @sendMenu="receiver" class="navigator"></Navigator> <Content class="content" :message="menu"></Content> </div> </template> <style scoped> .header{ height: 80px; border: 1px solid red; } .navigator{ width:20% ; height: 500px; border: 1px solid green; float: left; } .content{ width: 79%; height: 500px; border: 1px solid blue; float:right; } </style>
6.Vue3的路由机制router 6.1简介 什么是路由
定义:路由就是根据不同的URL地址展示不同的内容或页面。 通俗理解:路由就像是一个地图,我们要去不同的地方,需要通过不同的路线进行导航。 路由的作用
单页应用程序(SPA)中,路由可以实现不同视图之间的无刷新切换,提升用户体验; 路由还可以实现页面的认证和权限控制,保护用户的隐私和安全; 路由还可以利用浏览器的前进与后退,帮助用户更好地回到之前访问过的页面。 6.2 路由的使用 npm install vue-router
6.3 路由案例 src/components/Add.vue
<script setup> </script> <template> <div> <h1>add </h1> </div> </template> <style scoped> </style>
src/components/Home.vue
<script setup> </script> <template> <div> <h1>home</h1> </div> </template> <style scoped> </style>
src/components/List.vue
<script setup> </script> <template> <div> <h1>list </h1> </div> </template> <style scoped> </style>
src/components/Update.vue
<script setup> </script> <template> <div> <h1>Update </h1> </div> </template> <style scoped> </style>
src/routers/router.js
import {createRouter,createWebHashHistory} from 'vue-router' import Home from '../components/Home.vue' import List from '../components/List.vue' import Update from '../components/Update.vue' import Add from '../components/Add.vue' const router=createRouter ({ history :createWebHashHistory (), routes :[ { path :"/home" , component :Home }, { path :"/List" , component :List }, { path :"/Update" , component :Update }, { path :"/add" , component :Add }, { path :"/" , component :Home } ], }) export default router
App.vue
<script setup> </script> <template> <div> hello 李阳 <br> <hr> <router-link to="/home">home</router-link><br> <router-link to="/list">list</router-link><br> <router-link to="/add">add</router-link><br> <router-link to="/update">update</router-link><br> <!-- 该标签会被替换成具体的.vue --> <router-view></router-view> <hr> goodby 李阳 </div> </template> <style scoped> </style>
main.js
import { createApp } from 'vue' import App from './App.vue' import router from './routers/router' const app=createApp (App )app.use (router) app.mount ('#app' )
6.4 路由重定向 在router.js中添加
{ path :"/showAll" , redirect :"/list" },
表示我们请求showAll还会重定向到list
6.5 编程式路由 普通路由
<router-link to="/home">home</router-link><br>
这种路由,to中的内容目前是固定的,点击后只能切换/list对象编程式路由
通过useRouter,动态决定向那个组件切换的路由 在Vue 3和vue Router 4中,你可以使用useRouter来实现动态路由(编程式路由) 这里的useRouter方法返回的是一个router对象,你可以用它来做如导航到新页面、返回上一页面等操作。 案例
<script setup> import{useRouter} from 'vue-router' import{ref} from 'vue' const router =useRouter() let mypath=ref("") function showList(){ //编程式路由实现页面跳转 router.push("/list") //传对象 router.push({path:"list"}) } function goMyPage(){ router.push(mypath.value) } </script> <template> <div> hello 李阳 <br> <hr> <!-- 声明式路由 --> <router-link to="/home">home</router-link><br> <router-link to="/list">list</router-link><br> <router-link to="/add">add</router-link><br> <router-link to="/update">update</router-link><br> <!-- 编程式路由 --> <button @click="goMyPage()">go</button><input type="text" v-model="mypath"> <!-- 该标签会被替换成具体的.vue --> <hr> <router-view></router-view> <hr> goodby 李阳 </div> </template> <style scoped> </style>
import {createRouter,createWebHashHistory} from 'vue-router' import Home from '../components/Home.vue' import List from '../components/List.vue' import Update from '../components/Update.vue' import Add from '../components/Add.vue' const router=createRouter ({ history :createWebHashHistory (), routes :[ { path :"/home" , component :Home }, { path :"/List" , component :List }, { path :"/Update" , component :Update }, { path :"/add" , component :Add }, { path :"/" , component :Home }, { path :"/showAll" , redirect :"/list" }, ], }) export default router
6.6 路由传参 路径参数–params
在路径中使用一个动态字段来实现,我们称之为路径参数例如:查看数据详情/showDetail/1 ,1就是要查看详情的id,可以动态添值! 键值对参数-query
类似与get请求通过url传参,数据是键值对形式的例如:查看数据详情/showDetail?hid=1 , hid=1就是要传递的键值对参数 在Vue 3和Vue Router 4中,你可以使用useRoute这个函数从vue的组合式API中获取路由对象。 useRoute方法返回的是当前的route对象,你可以用它来获取关于当前路由的信息,如当前的路径、查询参数等。 案例需求:切换到ShowDetail.vue组件时,向该组件通过路由传递参数
6.6.1 路径传参数 /components/ShowDetail.vue
<script setup> // 接收传递过来的路径参数 import { useRoute } from 'vue-router'; import { ref ,onUpdated} from 'vue'; let languageId =ref(0) let languageName=ref("") let route=useRoute() languageId.value=route.params.id languageName.value=route.params.language onUpdated(()=>{ languageId.value=route.params.id languageName.value=route.params.language }) </script> <template> <div> <h1>ShowDetail接收路径参数 </h1> <h3>{{ languageId }}{{ languageName }}</h3> </div> </template> <style scoped> </style>
routers/router.js
import {createRouter,createWebHashHistory} from 'vue-router' import Home from '../components/Home.vue' import List from '../components/List.vue' import Update from '../components/Update.vue' import Add from '../components/Add.vue' import ShowDetail from '../components/ShowDetail.vue' const router=createRouter ({ history :createWebHashHistory (), routes :[ { path :"/showDetail/:id/:language" , component :ShowDetail }, { path :"/home" , component :Home }, { path :"/List" , component :List }, { path :"/Update" , component :Update }, { path :"/add" , component :Add }, { path :"/" , component :Home }, { path :"/showAll" , redirect :"/list" }, ], }) export default router
App.vue
<script setup> import{useRouter} from 'vue-router' import{ref} from 'vue' import ShowDetail from './components/ShowDetail.vue'; const router=useRouter() function showDetail(id,language){ //方式一 // router.push(`/showDetail/${id}/${language}`) //方式二 router.push({path:`/showDetail/${id}/${language}`}) } </script> <template> <div> <router-link to="/showDetail/1/java">声明式路由路径传参数</router-link> <button @click="showDetail(2,'PHP')"> 编程式路由路径传参</button> <hr> <router-view></router-view> </div> </template> <style scoped> </style>
6.6.2 键值对传参 草拟嘛了个逼 前端这么多东西怎么学啊 我草泥马
components/ShowDwtail2.vue
<script setup> // 接收传递过来的路径参数 //query 键值对cans import { useRoute } from 'vue-router'; import { ref ,onUpdated} from 'vue'; let languageId =ref(0) let languageName=ref("") let route=useRoute() languageId.value=route.query.id languageName.value=route.query.language onUpdated(()=>{ languageId.value=route.query.id languageName.value=route.query.language }) </script> <template> <div> <h1>ShowDetail键值对参数 </h1> <h3>{{ languageId }}{{ languageName }}</h3> </div> </template> <style scoped> </style>
router.js
import ShowDetail2 from '../components/ShowDetail2.vue' const router=createRouter ({ history :createWebHashHistory (), routes :[ { path :"/showDetail2" , component :ShowDetail2 } }) export default router
App.vue
<script setup> import{useRouter} from 'vue-router' import{ref} from 'vue' import ShowDetail from './components/ShowDetail.vue'; const router=useRouter() function showDetail(id,language){ //方式一 // router.push(`/showDetail/${id}/${language}`) //方式二 router.push({path:`/showDetail/${id}/${language}`}) } function showDetail2(id,language){ //方式一 router.push(`/showDetail2/?id=${id}&language=${language}`) } </script> <template> <div> <router-link to="/showDetail/1/java">声明式路由路径传参数</router-link> <button @click="showDetail(2,'PHP')"> 编程式路由路径传参</button> <hr> <router-link to="/showDetail2/?id=1&language=java">声明式路由键值对</router-link> <button @click="showDetail2(3,'C')"> 编程式路由键值对传参</button> <hr> <router-view></router-view> </div> </template> <style scoped> </style>
6.7 路由守卫 在Vue 3中,路由守卫是用于在路由切换期间进行一些特定任务的回调函数。路由守卫可以用于许多任务,例如验证用户是否已登录、在路由切换前提供确认提示、请求数据等。ue 3为路由守卫提供了全面的支持,并提供了以下几种类型的路由守卫
全局前置守卫:在路由切换前被调用,可以用于验证用户是否已登录、中断导航、请求数据等。 全局后置守卫:在路由切换之后被调用,可以用于处理数据、操作 DOM、记录日志等。 守卫代码放在router.js里面 router.beforeEach ( (to,from ,next )=> { } ) router.afterEach ( (to,from )=> { } ) export default router
6.8 路由练习 登录案例 登录以后才可以进入home ,否则必须进入login
components/Home.vue
<script setup> import{ref} from 'vue' import { useRouter } from 'vue-router'; let username=window.sessionStorage.getItem('username') const router=useRouter() function logout(){ //清除用户登录的信息 window.sessionStorage.removeItem("username") //跳转到login router.push("/login") } </script> <template> <div> <h1>home页面</h1> <h3> 欢迎{{ username }}登录</h3> <button @click="logout()">退出登录</button> </div> </template> <style scoped> </style>
components/Login.vue
<script setup> import {ref}from 'vue' import { useRouter } from 'vue-router' let username =ref('') let password=ref('') let router=useRouter() function login(){ //获取用户名密码 //root 123456 //登陆成功自动跳转到/home,失败不跳转,给出提示 if(username.value=='root' && password.value=='123456'){ //将用户名保存在浏览器中 window.sessionStorage.setItem("username",username.value) //路由跳转 /home router.push("/home") }else{ alert("用户名密码有误") } } </script> <template> <div> 账号:<input type="text" v-model="username"><br> 密码: <input type="password" v-model="password"><br> <button @click="login()">登录</button> </div> </template> <style scoped> </style>
routers/router,js
import {createRouter,createWebHashHistory} from 'vue-router' import Home from '../components/Home.vue' import Login from '../components/Login.vue' const router =createRouter ({ history :createWebHashHistory (), routes :[ { path :"/home" , component :Home }, { path :"/" , component :Home }, { path :"/login" , component :Login } ] }) router.beforeEach ((to,from ,next )=> { if (to.path =='/login' ){ next () }else { const username=sessionStorage .getItem ("username" ) if (null !=username){ next () }else { next ("/login" ) } } }) export default router
App.vue
<script setup> </script> <template> <div> <router-view></router-view> </div> </template> <style scoped> </style>
main.js
import { createApp } from 'vue' import router from './routers/router' import App from './App.vue' const app= createApp (App )app.use (router) app.mount ('#app' )
7.axios 7.1 promise 7.1.0 普通函数和回调函数 普通函数:正常调用的函数,一般函数执行完毕后才会继续执行下一行代码
回调函数:一些特殊的函数,表示未来才会执行的一些功能,后续代码不会等待该函数执行完毕就开始执行了
回调函数是一种基于事件的,自动调用函数 回调函数其他的代码不会等待回调函数执行完毕
简介 前端中的异步编程技术,类似Java中的多线程+线程结果回调!
Promise是异步编程的一种解决方案,比传统的解决方案–回调函数和事件–更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。 promise 特点
(1〉Promise对象代表一个异步操作,有三种状态,‘Pending`(进行中)、‘Resolved(已完成,又称Fulfilled)和Rejected’(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是“Promise’这个名字的由来,它的英语意思就是“承诺“,表示其他手段无法改变。
(2〉一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能。从’Pending ’变为“Resolved’和从’Pending ‘变为‘Rejected’。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
基本语法
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script > let promise =new Promise (function (resolve,reject ){ console .log ("founction" ) resolve () }) console .log ("ws1" ) promise.then ( function ( ){ console .log ("succeed" ) } ).catch ( function ( ){ console .log ("fail" ) } ) console .log ("ws2" ) </script > </head > <body > </body > </html >
async 和await的基本使用
async async帮助我们使用简洁的语法获得一个promise对象
async用户标识函数的async函数返回的结果就是一个promise 方法如果正常return结果,promise状态就是resolved return后的结果就是成功状态的返回值 方法中出现了异常,则返回的promise就是一个失败状态 async函数返回的结果如果是一个promise,则状态由内部的promise决定 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script > async function fun1 ( ) { return 10 } let promise=fun1 () promise.then ( function ( ){} ).catch ( function ( ){} ) </script > </head > <body > </body > </html >
await await帮助我们获取promise成功状态的返回值的关键字
await右边如果是一个普通值,则直接返回该值如果右边是promise,返回promise成功状态的结果 let res = await“张三“
let res = await Promise.resolve(“张三”) res =“张三”
await右边如果是一个失败状态的promise那么await会直接抛异常 await关键字必须在async修饰的函数中使用,async函数中可以没有await awat后边的代码会等待await执行完毕继续运行 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script > async function fun1 ( ) { return 10 } async function fun2 ( ){ let res =await fun1 () } </script > </head > <body > </body > </html >
听的我直恶心,跳了跳了
7.2 Axios 小案例
App.vue
<script setup> import { ref } from 'vue'; import axios from 'axios'; const message = ref(''); async function getLoveMessage() { try { const response = await axios({ method: 'get', url: '/api/api/rand.qinghua?format=json', data: {} }); console.log(response.data); if (response.data.code === 1) { message.value = response.data.content; } } catch (error) { console.error('请求出错:', error.message); } } </script> <template> <div> <h1>{{ message }}</h1> <button @click="getLoveMessage()">换一个~</button> </div> </template> <style scoped> </style>
vite.config.js
import { defineConfig } from 'vite' ;import vue from '@vitejs/plugin-vue' ;export default defineConfig ({ plugins : [vue ()], server : { proxy : { '/api' : { target : 'https://api.uomg.com' , changeOrigin : true , rewrite : (path ) => path.replace (/^\/api/ , '' ) } } } });
Axios get 和post方法
二、后端 2.1 HTTP HTTP超文本传输协议 (HTTP-Hyper Text transfer protocol),是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过十几年的使用与发展,得到不断地完善和扩展。它是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。客户端与服务端通信时传输的内容我们称之为报文。HTTP协议就是规定报文的格式。HTTP就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器发送给客户端的报文格式。实际我们要学习的就是这两种报文。客户端发送给服务器的称为“请求报文“,服务器发送给客户端的称为“响应报文““。
咦 这东西好耳熟,计网学过了
有点无聊,我们去学Servlet去吧
2.2 Servlet 记得我们大专的时候,这块老师讲的很详细,好像很重要的样子,李阳,这一块好好看好好学
李师傅要开始瞎编了:
首先当在浏览器我们要点击操作的时候,浏览器会发出请求,这里包含请求的信息,然后传给tomcat
tomcat会创建两个方法,获取我们在java中所写的要的操作,然后根据操作做出相应回来
demo-xml方式 前端验证用户名,当用户名已注册返回NO,未注册返回YES
哈哈哈哈哈哈哈 终于到实操了,理论太无聊了
代码部分 java
package com.sgg.servlet;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;public class UserServlet extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username" ); String info = "YES" ; if ("admin" .equals(username)) { info="NO" ; } PrintWriter writer = resp.getWriter(); writer.println(info); } }
html
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <form method ="get" action ="userServlet" > 用户名:<input type ="text" name ="username" /> <br > <input type ="submit" value ="校验" /> </form > </body > </html >
xml
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns ="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version ="4.0" > <servlet > <servlet-name > userServlet</servlet-name > <servlet-class > com.sgg.servlet.UserServlet</servlet-class > </servlet > <servlet-mapping > <servlet-name > userServlet</servlet-name > <url-pattern > /userServlet</url-pattern > </servlet-mapping > </web-app >
效果
重点讲解: <servlet-mapping > <servlet-name > userServlet</servlet-name > <url-pattern > /userServlet</url-pattern > </servlet-mapping >
的/userServlet与
<form method ="get" action ="userServlet" > 用户名:<input type ="text" name ="username" /> <br > <input type ="submit" value ="校验" /> </form >
的action要保持一致
url-pattern <servlet > <servlet-name > servlet1</servlet-name > <servlet-class > com.sgg.servlet.Servlet1</servlet-class > </servlet > <servlet-mapping > <servlet-name > servlet1</servlet-name > <url-pattern > /s1</url-pattern > <url-pattern > /xx1</url-pattern > </servlet-mapping >
这里简要说明一下流程,毕竟后面使用注解会方便很多
浏览器访问/xx1然后他会去找<servlet-name>servlet1</servlet-name>
然后在找到对应的路径包<servlet-class>com.sgg.servlet.Servlet1</servlet-class> </servlet>
/xx1
的路径唯一,其他的都不能使用
路径的精确批准与模糊匹配 精确匹配 /xx1
模糊匹配/*
/
匹配全部,但是不包含jsp文件/*
匹配全部,包含jsp文件/a/*
匹配前缀,/a/后面随便写都OK*.action
前缀模糊,匹配后缀也即是要以.action
结尾注解 嘿嘿嘿嘿嘿嘿 最喜欢的一集
注解可以帮我们省掉xml的配置信息,方便大家
folding green, 查看代码xml测试
<servlet > <servlet-name > servlet1</servlet-name > <servlet-class > com.sgg.servlet.Servlet1</servlet-class > </servlet > <servlet-mapping > <servlet-name > servlet1</servlet-name > <url-pattern > /s1</url-pattern > </servlet-mapping >
endfolding
folding yellow, 使用注解
@WebServlet("/s1") public class Servlet1 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("李阳你好" ); } }
endfolding
只需要在方法面前加@WebServlet,好耶好用
servletConfig和servletContext servletConfig 这东西好像是用来获取初始化信息的,感觉用的不多,知道就好了
xml-获取 <init-param>
里面的值
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns ="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version ="4.0" > <servlet > <servlet-name > servlet</servlet-name > <servlet-class > com.sgg.servlet.servlet1</servlet-class > <init-param > <param-name > keya</param-name > <param-value > valueA</param-value > </init-param > <init-param > <param-name > keyb</param-name > <param-value > valueB</param-value > </init-param > </servlet > <servlet-mapping > <servlet-name > servlet</servlet-name > <url-pattern > /servlet1</url-pattern > </servlet-mapping > </web-app >
java
package com.sgg.servlet;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Enumeration;public class servlet1 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = this .getServletConfig(); String keya = servletConfig.getInitParameter("keya" ); System.out.println("keya: " + keya); Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()){ String s = initParameterNames.nextElement(); System.out.println(s + ": " + servletConfig.getInitParameter(s)); } } }
使用注解方式
@WebServlet( urlPatterns = "/servlet1", initParams = {@WebInitParam(name = "keya",value = "valuea"),@WebInitParam(name = "keyb",value = "keyB")} )
完整代码
@WebServlet( urlPatterns = "/servlet1", initParams = {@WebInitParam(name = "keya",value = "valuea"),@WebInitParam(name = "keyb",value = "keyB")} ) public class servlet1 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletConfig servletConfig = this .getServletConfig(); String keya = servletConfig.getInitParameter("keya" ); System.out.println("keya: " + keya); Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()){ String s = initParameterNames.nextElement(); System.out.println(s + ": " + servletConfig.getInitParameter(s)); } }
servletContext ServletContext对象有称呼为上下文对象,或者叫应用域对象(后面统一讲解域对象)。容器会为每个app创建一个独立的唯一的ServletContext对象 ServletContext对象为所有的Servlet所共享 ServletContext可以为所有的servlet提供初始配置参数 简而言之:为所有的servlet提供所有参数(ServletConfig是为某一个)
功能1:获取初始化值 package com.sgg.servlet;import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Enumeration;@WebServlet("/servlet2") public class servlet2 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); ServletContext servletContext1 = req.getServletContext(); System.out.println( servletContext1); System.out.println( servletContext); String encoding = servletContext.getInitParameter("encoding" ); System.out.println("encoding: " +encoding); Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String initParameterName = initParameterNames.nextElement(); System.out.println(initParameterName+"=" +servletContext.getInitParameter(initParameterName)); } } }
xml
<context-param > <param-name > encoding</param-name > <param-value > UTF-8</param-value > </context-param > <context-param > <param-name > username</param-name > <param-value > liyang</param-value > </context-param >
演示
好无聊好无聊的课
功能2:获取tomcat路径和文件路径 package com.sgg.servlet;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.FileOutputStream;import java.io.IOException;@WebServlet("/servlet3") public class servlet3 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); String path=servletContext.getRealPath("upload" ); System.out.println(path); FileOutputStream fileOutputStream = new FileOutputStream (path+"/a.txt" ); String contextPath = servletContext.getContextPath(); System.out.println(contextPath); } }
啊啊啊啊啊啊,太无聊了
功能3:域对象的API 域对象:一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的戢,共享数据的范围也不同 ServletContext代表应用,所以ServletContext域也叫作应用域,是webapp中最大的域,可以在本应用内实现数据的共享和传递 webapp中的三大域对象,分别是应用域,会话域,请求域
放元素 servlet1
package com.sgg.servlet;import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Enumeration;@WebServlet( urlPatterns = "/servlet1", initParams = {@WebInitParam(name = "keya",value = "valuea"),@WebInitParam(name = "keyb",value = "keyB")} ) public class servlet1 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); servletContext.setAttribute("keya" , "va" ); } }
sevalet3读取
package com.sgg.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.FileOutputStream; import java.io.IOException; /** * Created with IntelliJ IDEA. * * @Author: 李阳 * @Date: 2024/12/29/11:01 * @Description:往upload里面写入文件信息-io流 */ @WebServlet("/servlet3") public class servlet3 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); //从域中读取数据 String ka = (String) servletContext.getAttribute("keya"); System.out.println(ka); } }
控制台读取到了sevalet1里面存放的元素
妙秒喵🐱
修改 servlet1
servletContext.setAttribute("keya", "va"); servletContext.setAttribute("keya", "keyB");
烙铁,没毛病哦
HttpServaletRequest HttpServletRequest是一个接口,其父接口是ServletRequest HttpServietRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入 HttpServletRequest代表客户端发来的请求,所有请求中的信息都可以通过该对象获得 获取请求行信息相关的
获取请求头
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Enumeration;import java.util.HashMap;@WebServlet("/servlet04") public class servlet4 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(req.getMethod()); System.out.println(req.getScheme()); System.out.println(req.getProtocol()); System.out.println(req.getRequestURL()); System.out.println(req.getRequestURI()); System.out.println(req.getLocalPort()); System.out.println(req.getServerPort()); System.out.println(req.getRemotePort()); Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String value = req.getParameter(name); System.out.println(name+"=" +value); } String accept = req.getHeader("Accept" ); System.out.println("accept:" +accept); } }
获取请求参数
java
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Arrays;import java.util.Enumeration;import java.util.Map;@WebServlet("/servlet05") public class servlet05 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(req.getParameter("username" )); System.out.println(req.getParameter("password" )); String[] hobbies = req.getParameterValues("hobby" ); System.out.println(Arrays.toString(hobbies)); Enumeration<String> parameterNames = req.getParameterNames(); while (parameterNames.hasMoreElements()) { String parameterName = parameterNames.nextElement(); String[] parameterValues = req.getParameterValues(parameterName); if (parameterValues.length>1 ){ System.out.println(parameterName+"= " +Arrays.toString(parameterValues)); }else { System.out.println(parameterName+"= " +parameterValues[0 ]); } } System.out.println("-------------------------------" ); Map<String, String[]> parameterMap = req.getParameterMap(); for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) { System.out.println(stringEntry.getKey()+"= " +Arrays.toString(stringEntry.getValue())); } } }
html
<!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > 测试httpServlet</title > </head > <body > <form method ="get" action ="servlet05" > 姓名:<input type ="text" name ="username" > <br > 密码<input type ="password" name ="password" > <br > 爱好: <input type ="checkbox" name ="hobby" value ="1" > 唱<br > <input type ="checkbox" name ="hobby" value ="2" > 跳<br > <input type ="checkbox" name ="hobby" value ="3" > rap<br > <input type ="checkbox" name ="hobby" value ="4" > 篮球<br > <input type ="submit" > </form > </body > </html >
post或者get都可以拿到
其他api
HttpServletResponse HttpServletResponse是一个接口,其父接口是ServletResponse HttpServletResponse是Tomcat预先创建的,在Tomcat调用service方法时传入 HttpServletResponse代表对客户端的响应,该对象会被转换成响应的报文发送给客户端,通过该对象我们可以设置响应信息
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@WebServlet("/servlet06") public class servlet06 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String info="<h1>李阳</h1>" ; resp.setStatus(200 ); resp.setHeader("sss" ,"value1" ); resp.setContentType("text/html" ); resp.setContentLength(info.getBytes().length); PrintWriter writer = resp.getWriter(); writer.write(info); } }
2.3请求与转发 请求转发生活举例:张三找李四借钱,李四没有,李四找王五,让王五借给张三
响应重定向生活举例:张三找李四借钱,李四没有,李四让张。去找王五,张三自己再去找王五借钱
请求转发通过HttpServletRequest实现,响应重定向通过HttpServletResponse实现
1请求转发时,请求和响应对象会继续传递给下一个资源
2请求中的参数可以继续向下传递
3请求转发时服务器内部的行为,客户端是不知道的
4客户端只产生了一次请求
selectA处理不了给了B,B再响应给客户端
这个就是定义转发的代码
req.getRequestDispatcher("servletB" ).forward(req, resp);
servletA
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/servletA") public class servletA extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servletA" ); req.getRequestDispatcher("servletB" ).forward(req, resp); } }
servletB
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/servletB") public class servletB extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servletB" ); } }
转发到页面
@WebServlet("/servletA") public class servletA extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servletA" ); String money = req.getParameter("money" ); System.out.println("ServletA" +money); req.getRequestDispatcher("WEB-INF/b.html" ).forward(req, resp); } }
总结-面试要背 请求转发通过HttpServletRequest对象获取请求转发器实现 请求转发是服务器内部的行为,对客户端是屏蔽的 客户端只发送了一次请求,客户端地址栏不变 服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源 因为全程只有一个HttpServletRequset对象,所以请求参数可以传递,请求域中的数据也可以传递 请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转 请求转发可以转发给WEB-INF下受保护的资源 请求转发不能转发到本项目以外的外部资源 2.4 重定向 客户端发送请求给A,A处理不了,然后A就返回response,把目标头302和location:目标地址 返回给浏览器,浏览器再通过目标地址去请求其他功能页面
特点 响应重定向通过HttpServletResponse对象的sendRedirect方法实现 响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的,客户端的行为 客户端至少发送了两次请求,客户端地址栏是要变化的 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源 因为全程产生了多个HttpServletRequset对象,所以请求参数不可以传递,请求域中的数据也不可以传递 重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转 重定向不可以到给WEB-INF下受保护的资源 重定向可以到本项目以外的外部资源 package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/servlet1") public class servlet1 extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet1" ); resp.sendRedirect("servlet2" ); } }
2.5 解决响应乱码 resp.setContentType("text/html;charset=utf-8" ); resp.getWriter().write("你好,hello" );
2.6 MVC MVC (Model view Controller)是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
2.7 会话管理 ·无状态就是不保存状态,即无畎态协议(stateless),HTTP协议自身不对请求和响应之间的通信状态进行保存,也就是说,在HTTP协议这个级别协议对于发送过的请求或者响应都不做持久化处理 简单理解:浏览器发送请求.服务器接收并响应,但是服务器不记录请求是否来自哪个浏览器,服务器没记录浏览器的特征,就是客户端的状态
2.7.1 cookie cookie是一种客户端会话技术,cookie由服务端产生,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。
服务端创建cookie,将cookie放入响应对象中,Tomcat容器将cookie转化为set-cookie响应头,响应给客户端。 客户端在收到cookie的响应头时,在下次请求该服务的资源时,会以cookie请求头的形式携带之前收到的Cookie cookie是一种键值对格式的数据,从tomcat8.5开始可以保存中文,但是不推荐 由于cookie是存储于客户端的数据,比较容易暴露,一般不存储一些敏感或者影响安全的数据 生存周期 会话级Cookie
服务器端并没有明确指定Cookie的存在时间。
在浏览器端,Cookie数据存在于内存中。
只要浏览器还开着,Cookie数据就一直都在。
浏览器关闭,内存中的cookie数据就会被释放·
持久化Cookie
会话级代码演示 package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/servletA") public class ServletA extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie cookie1 = new Cookie ("kaya" ,"vala" ); Cookie cookie2 = new Cookie ("kayb" ,"valb" ); resp.addCookie(cookie1); resp.addCookie(cookie2); } }
捕获
package com.sgg.servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/servletB") public class ServletB extends HttpServlet { @Override protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie[] cookies = req.getCookies(); for (Cookie cookie : cookies) { System.out.println(cookie.getName() + " " + cookie.getValue()); } } }
持久化 Cookie cookie1 = new Cookie ("kaya" ,"vala" ); Cookie cookie2 = new Cookie ("kayb" ,"valb" ); cookie1.setMaxAge(3600 );
2.7.2 Session session要和cookie配合使用
HttpSession是一种保留更多信息在服务端的一种技术,服务器会为每一个客户端开辟一块内存空间,即session对象.客户端在发送请求时,都可以使用自已的session.这样服务端就可以通过session来记录某个客户端的状态了
服务端在为客户端创建session时,会同时将session对象的id,即JSESSIONID以cookie的形式放入响应对象。 后端创建完session后,客户端会收到一个特殊的cookie,叫做JSESSIONID 客户端下一次请求时携带JSESSIONID,后端收到后,根据JSESSIONID找到对应的session对象。 通过该机制,服务端通过session就可以存储一些专门针对某个客户端的信息了 session也是域对象(后续详细讲解) 2.7.3 三大域对象 域对象:一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同
web项目中,我们一定要熟练使用的域对象分别是请求域,会话域,应用域 请求域对象是HttpServletRequest ,传递数据的范围是一次请求之内及请求转发。 会话域对象是HttpSession,传递数据的范围是一次会话之内,可以跨多个请求。 应用域对象是ServletContext,传递数据的范围是本应用之内,可以跨多个会话
域对象的使用 API 功能 void setAttribute(String name,String value) 向域对象中添加/修改数据 Object getAttribute(String name) 从域对象中获取数据 removeAttribute(String name) 移除域对象中数据
2.8 过滤器-Filter 1.概述 Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口 ·Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFiter方法 Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应 Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理 Filter是GOF中责任链模式的典型案例 。Filter的常用应用包括但不限于:登录权限检查,解决网站乱码,过滤敏感字符,日志记录,性能分析….. 2.举例 公司前台对来访人员进行审核,如果是游客则拒绝进入公司,如果是客户则放行.客户离开时提醒客户不要遗忘物品 停车场保安对来访车辆进行控制,如果没有车位拒绝进入,如果有车位,发放停车卡并放行,车辆离开时收取请车费 地铁验票闸机在人员进入之前检查票,没票拒绝进入,有票验票后放行,人员离开时同样验票 3.应用 日志的记录 ·性能的分析。 乱码的处理· 事务的控制· 登录的控制· 跨域的处理 … …
4.格式 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app > <display-name > Archetype Created Web Application</display-name > <filter > <filter-name > logginFilter</filter-name > <filter-class > com.sgg.filters.LoggingFilter</filter-class > </filter > <filter-mapping > <filter-name > logginFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > </web-app >
2.8.5 生命周期 过滤器作为web项目的组件之一和Servlet的生命周期类似,略有不同,没有servlet的load-on-startup的配置,默认就是系统启动立刻构造
阶段 对应方法 执行时机 执行次数 创建对象 构造器 web应用启动时 1 初始化方法 void init(FilterConfig filterConfig) 构造完毕 1 过滤请求 void doFilter(ServietRequest servletRequest, ServietResponse servletResponse,FilterChainfilterChain) 每次请求 多次 销毁 default void destroy() web应用关闭时 1次
代码我很懒给略了
2.8.6 过滤器链的使用 一个web项目中,可以同时定义多个过滤器,多个过滤器对同一个资源进行过滤时,工作位置有先后,整体形成一个工作链,称之为过滤器链
过滤器链中的过滤器的顺序由filter-mapping
顺序决定 每个过滤器过滤的范围不同,针对同一个资源来说,过滤器链中的过滤器个数可能是不同的 如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低
工作流程
过滤器链中的过滤器的顺序由filter-mapping
顺序决定
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app > <display-name > Archetype Created Web Application</display-name > <filter > <filter-name > filter1</filter-name > <filter-class > com.sgg.filters.Filter1</filter-class > </filter > <filter > <filter-name > filter2</filter-name > <filter-class > com.sgg.filters.Filter2</filter-class > </filter > <filter > <filter-name > filter3</filter-name > <filter-class > com.sgg.filters.Filter3</filter-class > </filter > <filter-mapping > <filter-name > filter1</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter-mapping > <filter-name > filter2</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter-mapping > <filter-name > filter3</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > </web-app >
2.8.6.1 使用注解方式 @WebFilter("/*")
使用注解方式代码举例
package com.sgg.filters;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import java.io.IOException;@WebFilter("/*") public class Filter1 implements Filter { @Override public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter1 方行前代码" ); filterChain.doFilter(servletRequest, servletResponse); System.out.println("filter1放行后代码" ); } }
使用注解后,控制执行顺序需要改变忘记命名顺序,字典的前后区别
2.9 监听器 监听器:专门用于对域对象对象身上发生的事件或状态改变进行监听和相应处理的对象
监听器是GOF设计模式中,观察者模式的典型案例 观察者模式:当被观察的对象发生某些改变时,观察者自动采取对应的行动的一种设计模式 监听器使用的感受类似Js中的事件,被观察的对象发生某些情况时,自动触发代码的执行。 监听器并不监听web项目中的所有组件,仅仅是对三大域对象做相关的事件监听 监听器的分类
web中定义八个监听器接口作为监听器的规范,这八个接口按照不同的标准可以形成不同的分类 按监听的对象划分application域监听器 ServletContextListener
ServletContextAttributeListener session域监听器 HttpSessionListener HttpSessionAttributeListener HttpSessionBindingListener HttpSessionActivationListener request域监听器 ServletRequestListener ServletRequestAttributeListener 按监听的事件分域对象的创建和销毁监听器 ServletContextListener HttpSessionListener ServletRequestListener 域对象数据增删改事件监听器 ServletContextAttributeListener HttpSessionAttributeListener ServletRequestAttributeListener 其他监听器 HttpSessionBindingListener HttpSessionActivationListener 2.9.2 监听器的六个主要接口 2.9.2.1 application域监听器 ServletContextListener 监听ServletContext对象的创建与销毁
方法名 作用 contextInitialized(ServletContextEvent sce) ServletContext创建时调用 contextDestroyed(ServletContextEvent sce) ServletContext销毁时调用
ServletContextEvent对象代表从ServletContext对象身上捕获到的事件,通过这个事件对象我们可以获取到ServletContext对象。 ServletContextAttributeListener 监听ServletContext中属性的添加、移除和修改
方法名 作用 attributeAdded(ServletContextAttributeEvent scab) 向ServletContext中添加属性时调用 attributeRemoved(ServletContextAttributeEvent scab) 从ServletContext中移除属性时调用 attributeReplaced(ServletContextAttributeEvent scab) 当ServletContext中的属性被修改时调用
ServletContextAttributeEvent对象代表属性变化事件,它包含的方法如下: 方法名 作用 getName() 获取修改或添加的属性名 getValue() 获取被修改的属性值 getServletContext() 获取ServletContext对象
ServletContextListener 应用域代码 package com.sgg.listen;import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import javax.servlet.annotation.WebListener;@WebListener public class MyApplicationLister implements ServletContextListener { @Override public void contextInitialized (ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println(servletContext.hashCode()+"应用域被初始化了" ); } @Override public void contextDestroyed (ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println(servletContext.hashCode()+"应用域被销毁" ); } }
[2025 -01 -19 01 :17 :29 ,228 ] 工件 demo9-listen:Web exploded: 正在部署工件,请稍候… 1135537166 应用域被初始化了1135537166 应用域被销毁已与服务器断开连接
ServletContextAttributeListener监听数据变化代码 package com.sgg.listen;import javax.servlet.*;import javax.servlet.annotation.WebListener;@WebListener public class MyApplicationLister implements ServletContextListener , ServletContextAttributeListener { @Override public void contextInitialized (ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println(servletContext.hashCode()+"应用域被初始化了" ); } @Override public void contextDestroyed (ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); System.out.println(servletContext.hashCode()+"应用域被销毁" ); } @Override public void attributeAdded (ServletContextAttributeEvent scae) { ServletContext servletContext = scae.getServletContext(); String key = scae.getName(); Object value = scae.getValue(); System.out.println(servletContext.hashCode()+"应用域增加了" +key+": " +value); } @Override public void attributeRemoved (ServletContextAttributeEvent scae) { ServletContext servletContext = scae.getServletContext(); String key = scae.getName(); Object value = scae.getValue(); System.out.println(servletContext.hashCode()+"应用域移除了" +key+": " +value); } @Override public void attributeReplaced (ServletContextAttributeEvent scae) { ServletContext servletContext = scae.getServletContext(); String key = scae.getName(); Object value = scae.getValue(); Object newValue = servletContext.getAttribute(key); System.out.println(servletContext.hashCode()+"应用域修改了" +key+": " +value+"为" +newValue); } }
已连接到服务器 [2025 -01 -19 02 :25 :48 ,245 ] 工件 demo9-listen:Web exploded: 正在部署工件,请稍候… 762047125 应用域被初始化了762047125 应用域增加了keya: valuea762047125 应用域修改了keya: valuea为valuexx762047125 应用域移除了keya: valuexx762047125 应用域被销毁19 -Jan-2025 14 :26 :57.614 信息 [main] org.apache.coyote.AbstractProtocol.stop 正在停止ProtocolHandler ["http-nio-8080" ]19 -Jan-2025 14 :26 :57.630 信息 [main] org.apache.coyote.AbstractProtocol.destroy 正在销毁协议处理器 ["http-nio-8080" ]已与服务器断开连接
日程管理 link 日程表项目后端系统,https://github.com/lyay23/atguigu-scheduleSystem
前端工程化 lyay23/atguigu-vue-scheduleSystem (github.com)
错误 1.实体类名称不匹配 我在经行测试的时候遇到了一些错误
控制台说这个名字不匹配
检查发现是因为我的实体类名称不叫uid,而查询报错
解决方案1:为sql语句的uid取别名与pojo的一样
方案2:修改pojo与数据库的uid一致
两种方法都可行
2.中文乱码问题
resp.setContentType("text/html;charset=utf-8" );
设置中文