既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
400异常----传参相关的异常
get方法长度限制
400异常,加了@RequestParam(value = “name”) 必须传值
400异常,后端类型是Integer,前端传的是string,转换失败
400异常,日期格式转换失败
Failed to convert from type [java.lang.String] to type [java.util.Date] for value ‘2021-5-28’; nested exception is java.lang.IllegalArgumentException]
404异常----页面找不到
302重定向—地址变化
【bug】302重定向,ERR_TOO_MANY_REDIRECTS,如果配置类中的,excludePathPatterns忘记加第一个反斜杠 /
报错:ERR_TOO_MANY_REDIRECTS
原因:.excludePathPatterns里面的路径反斜杠没加
304—客户端有缓存
访问静态资源时,如果服务器认为静态文件没有变,就会返回304状态码
再次访问时,服务器认为自己的图片没变,所以报304
存在问题,如果验证码是一张图片,那浏览器清理的缓存,结果用户请求服务器的静态图片时,就拿不到了,解决方法,骗一下服务器,每次加一个?,服务器就会再次发一下
405异常:服务器只能处理post,浏览器请求的是get方法
网页状态码415
报错信息:
spring后台的报错:
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported]
浏览器的报错:
报错原因:传的是字符串,接收的时候加了@RequestBody,表示用对象接收,就报415异常
解决方案:
// public ResData queryById(@RequestBody Integer id){ // TODO:415异常
public ResData queryById(Integer id){
// axios.post("/build/id",this.id)// TODO:415异常
axios.get("/build/id?id="+this.id)
深入理解axios的所谓的post请求:
在post请求中,通过用new URLSearchParams(),发送post请求,其实本质是以String类型的键值对发送给后端的
let params = new URLSearchParams();
let listParam = {"buildingIdList":this.selectedBuildingList}
params.set("buildingList",this.selectedBuildingList)
params.set("areaMin",this.areaMin)
params.set("areaMax",this.areaMax)
params.set("areaOrderASC",this.areaOrderASC)
params.set("areaOrderDESC",this.areaOrderDESC)
console.log(listParam)
console.log(params)
axios.post("/owner/query/house",params)
<string,string>类型的键值对
通常看到的表单数据是这样,
本质其实就是下面这个,和get请求就差一个?,区别是一个是拼在浏览器的地址栏的路径上,另一个是放在请求头里面;
所以在上面的请求中,报错了,415异常
Spring后台的信息:
Using 'application/json', given [application/json, text/plain, \*/\*] and supported [application/json, application/\*+json, application/json, application/\*+json]
Using ‘application/json’, given [application/json, text/plain, /] and supported [application/json, application/+json, application/json, application/+json]
这个错误通常出现在尝试使用 “application/json” 作为响应类型的API端点上。它是一个比较普遍的错误,通常是由于客户端在发送请求时没有正确设置请求头导致的。
这个错误信息的含义是,虽然该API端点支持 “application/json” 响应类型,但客户端发出的请求头中可能没有包含正确的 “Accept” 值。“Accept” 值指定了客户端能够接受的 MIME 类型。在这个例子中,客户端似乎已经将请求头中的 “Accept” 设置为 “text/plain” 或 “/”,但是服务器只支持 “application/json” 响应类型,因此会出现这个错误。
要解决这个问题,您需要确保客户端请求头中的 “Accept” 值设置为 “application/json”,或者可以同时支持多种响应类型。如果您正在使用 JavaScript 中的 XMLHttpRequest 或 Fetch API,则可以使用以下代码来设置请求头:
// 对于 XMLHttpRequest
xhr.setRequestHeader("Accept", "application/json");
// 对于 Fetch API
fetch(url, {
headers: {
"Accept": "application/json"
}
});
这样设置请求头之后,应该就能够成功地获得 “application/json” 响应类型了。
上述问题解决方案
这种方式会报异常!!!
/\*\*
\* 查询所有空闲的房子,显示到左边的框里面 TODO:后面再全查询的基础上进行
\*/
List<House> queryAllNoIntoHouse(
@Param("buildingIdList") List<Integer> buildingIdList, // 楼栋
@Param("storey") Integer storey, // 楼层
@Param("areaMin") Double areaMin, // 面积
@Param("areaMax") Double areaMax, // 面积
@Param("areaOrderASC") Boolean areaOrderASC,
@Param("areaOrderDESC") Boolean areaOrderDESC,// 排序
@Param("status") Boolean... status // 如果为false,则可以查询到非空闲房子,其他情况 都是查询空闲房子
);
SQL语句 <where,choose,when,otherwise,foreach,if>
<select id="queryAllNoIntoHouse" resultType="house">
SELECT
c_house.id,
c_owner_house.ownerId,
c_building.num,c_building.floors,c_building.unit,
c_house.storey,c_house.roomNum,c_house.area,c_house.into_date,c_house.status,c_house.building_id,
user_owner.realname AS ownerName
FROM c_house
LEFT JOIN c_building ON c_building.id = c_house.building_id
LEFT JOIN c_owner_house ON c_owner_house.houseId = c_house.id
LEFT JOIN user_owner ON user_owner.id = c_owner_house.ownerId
<where>
<choose>
<when test="buildingIdList!=null and buildingIdList.size()>0">
building_id IN
<foreach collection="buildingIdList" open="(" separator="," close=")" item="id">
#{id}
</foreach>
</when>
<otherwise>
<!-- 默认全查-->
</otherwise>
</choose>
<if test="storey!=null">
AND c_house.storey=#{storey}
</if>
<if test="areaMin!=null">
AND c_house.area >= #{areaMin}
</if>
<if test="areaMax!=null">
AND c_house.area <= #{areaMax}
</if>
<choose>
<when test="status!=null and status.length>0 and !status[0]">
<!-- 如果为false,则可以查询到非空闲房子-->
</when>
<otherwise>
AND !status
</otherwise>
</choose>
</where>
<if test="areaOrderASC">
ORDER BY c_house.area
</if>
<if test="areaOrderDESC">
ORDER BY c_house.area DESC
</if>
</select>
前后端交互controller层,用专门前后端交互的实体类接收参数
// 2.处理搜索请求
// 默认显示所有可以选择的房间,放到左侧的框里,如果选择,双击,这条数据跳到右边的框里
@RequestMapping("/query/house")
@ResponseBody
public ResData queryHouse(
// @RequestParam(value = "buildingList", defaultValue = "List[]") List<Building> buildingList, // 楼栋
// Integer storey, // 楼层,没有用到
// Double areaMin,
// Double areaMax,
// @RequestParam(value = "areaOrderASC",defaultValue = "false") Boolean areaOrderASC,
// @RequestParam(value = "areaOrderDESC",defaultValue = "false") Boolean areaOrderDESC
@RequestBody HouseFront houseFront
){
Double areaMax = houseFront.getAreaMax();
Double areaMin = houseFront.getAreaMin();
Boolean areaOrderASC = houseFront.getAreaOrderASC();
Boolean areaOrderDESC = houseFront.getAreaOrderDESC();
Integer storey = houseFront.getStorey();
List<Building> buildingList = houseFront.getBuildingList();
List<Integer> buildingIds = buildingList.stream().map(Building::getId).collect(Collectors.toList());
System.out.println("查询条件:"
+areaMin+"/"
+areaMax+"/"
+buildingIds+"/"
+storey+"/"
);
// 大小的问题
if (!StringUtils.isBlank(areaMin) && !StringUtils.isBlank(areaMax)){
if (areaMin.compareTo(areaMax)>0){
return new ResData(1002, "最小面积不能大于最大面积", null);
}
}
// 这个排序顺序不能两个都是true
if (areaOrderASC && areaOrderDESC){
return new ResData(1003, "排序条件冲突", null);
}
List<House> list = houseService.queryAllNoIntoHouse(buildingIds, storey, areaMin, areaMax, areaOrderASC, areaOrderDESC, true);
list.forEach(System.out::println);
return new ResData(200, "ok", list);
}
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增业主</title>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
<script src="/js/jquery-3.5.1.js"></script>
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/vue.min-v2.5.16.js"></script>
</head>
<body>
<div id="app">
<br>
录入业主基础信息:<br>
用户名: <input type="text" v-model="username">
真实姓名:<input type="text" v-model="realname">
电话号码:<input type="text" v-model="tel"><br>
身份证号:<input type="text" v-model="identity">
性别:
<input type="radio" v-model="gender" value="男">男
<input type="radio" v-model="gender" value="女">女
<br>
备注信息:<textarea v-model="notes" rows="3" cols="22"></textarea><br>
<br>
录入选房信息:<br>
<div>
<!-- 搜索所有可以选择的房子-->
楼栋编号:
<select v-model="buildingId">
<option value="">--请选择楼栋--</option>
<option v-for="building in buildingList" :value="building.id">{{building.num}}-{{building.unit}}</option>
</select>
<button @click="addBuildingId">添加楼栋</button>
<button @click="resetSelectBuildsBtn">重选楼栋</button>
<br>
选中的楼栋为:
<select multiple style="width: 100px" @dbclick="removeSelectedBuildingsBtn">
<option v-for="building in selectedBuildingList" :value="building.id">{{building.num}}-{{building.unit}}</option>
</select>
楼层:
<select v-model="selectFloor">
<option value="">-选择楼层--</option>
<option v-for="floors in floorList" :value="floors">{{floors}}层</option>
</select>
面积:
<input type="text" v-model="areaMin" style="width: 50px" placeholder="小">---
<input type="text" v-model="areaMax" style="width: 50px" placeholder="大">
<button @click="areaASC">面积升序</button>
<button @click="areaDESC">面积降序</button>
<button @click="searchHouseBtn">搜索房子</button>
<button @click="searchHouseBtnClr">重置搜索</button><br>
</div>
<!-- TODO:可以选的房子的左侧的框-->
<!-- canSelectHouse-->
可选的房子为:
<select multiple style="width: 200px" @dblclick="selectHouseDbc">
<option v-for="house in canSelectHouse" :value="house.id">
{{house.num}}--{{house.unit}}--{{house.roomNum}}--{{house.area}}
</option>
</select>
选中的房子为:
<select multiple style="width: 200px" @dblclick="removeSelectedHouseDbc">
<option v-for="house in selectedHouse" :value="house.id">
{{house.num}}--{{house.unit}}--{{house.roomNum}}--{{house.area}}平米
</option>
</select>
<br>
<button @click="add">添加</button>
<button @click="reset">重置</button><br>
<br>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
// 首先是用户的基础信息
username:"",
realname:"",
tel:"",
gender:"男",
identity:"",
buildingId:"",
houseId:"",
notes:"",
// 然后是查询的数据
// 然后是选中的楼栋的id,1栋1单元...
floorList : Array.from({ length: 12 }, (v, i) => i + 1), // 最大有12层楼,因此这里可以选择1到12
selectedBuildingList:[], // List<Building> buildingList, // 楼栋
selectFloor:"", // 楼层
areaMin:"", // 面积
areaMax:"", // 面积
// 和排序相关的
areaOrderASC:false,
areaOrderDESC:false,
// 在左侧边框里面显示可以选择的所有房间信息
canSelectHouse:[],
// 在右侧框里面显示已经选择的所有房间信息
selectedHouse:[],
buildingList:[]
},
methods:{
searchHouseBtnClr(){
// 重置搜索
this.selectedBuildingList =[]
this.buildingId = ""
this.selectFloor="" // 楼层
this.areaMin="" // 面积
this.areaMax="" // 面积
// 和排序相关的
this.areaOrderASC=false
this.areaOrderDESC=false
this.queryHouse();
},
// 如果选中了一个楼栋,就添加一个楼栋来,如果有重复的就不添加
addBuildingId(){
let selected = this.buildingList.find(b=>b.id===this.buildingId)
// 这个selected是一个 building对象
console.log(selected)
// 只有selected里面有值,并且没有重复的时候才能添加进来
if (selected && !this.selectedBuildingList.find(b=>b.id===selected.id)){
this.selectedBuildingList.push(selected)
}
},
// 如果双击选中的楼栋,则删除已经选中的楼栋
removeSelectedBuildingsBtn(event){
const optionValue = event.target.value; // 获取双击的对象的值
this.selectedBuildingList = this.selectedBuildingList.filter(building=>building.id != optionValue)
},
// 在可选的房子的框里面双击,则在选中的房子的框里面加这个房子,并且在可选的房子的框里面删除被选的房子
selectHouseDbc(event){
const optionValue = event.target.value; // 获取双击的对象的值
// TODO:注意两点,这个过滤后的还是一个集合,需要获取第一个元素,另外要用== 不要用===
const house = this.canSelectHouse.filter(house=>house.id == optionValue)[0]
console.log(house)
this.selectedHouse.push(house)
this.canSelectHouse = this.canSelectHouse.filter(house=>house.id != optionValue)
console.log(this.canSelectHouse)
console.log(this.selectedHouse)
},
removeSelectedHouseDbc(event){
const optionValue = event.target.value; // 获取双击的对象house
console.log(optionValue)
const house = this.selectedHouse.filter(house=>house.id == optionValue)[0]
this.selectedHouse = this.selectedHouse.filter(house=>house.id !=optionValue)
this.canSelectHouse.push(house)
},
//如果选中了一个房子,就添加一个进来,如果有重复的就不添加
addHouseId(){
const selectedOption = this.allhouseList.find(house=>house.id===this.houseId);
if (selectedOption && !this.houseList.find(house => house.id === selectedOption.id)) {
this.houseList.push(selectedOption);
}
},
removeSelectedOption(event) {
const optionValue = event.target.value;//获取双击的对象的值
console.log(optionValue);
this.houseList = this.houseList.filter(house => house.id != optionValue);
},
add(){
let param = {};
param.username = this.username;
param.realname = this.realname;
param.tel = this.tel;
param.gender = this.gender;
param.identity = this.identity;
param.notes = this.notes;
param.houseList = this.selectedHouse;
axios.post("/owner/add",param)
.then(response=>{
if(response.data.code==200)
![img](https://img-blog.csdnimg.cn/img_convert/46f34b34a5d091288db3bd466f3ad8c9.png)
![img](https://img-blog.csdnimg.cn/img_convert/72c3f09356014ddb34ab26a66e7e80d0.png)
![img](https://img-blog.csdnimg.cn/img_convert/64505794b073f3639827b2c0ca9df466.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
identity;
param.notes = this.notes;
param.houseList = this.selectedHouse;
axios.post("/owner/add",param)
.then(response=>{
if(response.data.code==200)
[外链图片转存中...(img-eqk7cMVH-1715554841253)]
[外链图片转存中...(img-ysaCZ2P3-1715554841253)]
[外链图片转存中...(img-cHXzc6xI-1715554841253)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**