SpringBoot+vue旅游项⽬总结
Springboot+vue旅游项⽬⼩总结
业务简单,对提升业务能⼒没什么⼤的帮助,更多的是可以熟悉开发流程和编码。
白茶和绿茶的区别1.表结构
仅仅三张表,分别为⽤户表,省份表和景点表,其中省份表和景点表为⼀对多的关系。
⽤户表(t_ur):
省份表(t_province):
景点表(t_place):
2.相关配置
rver.port=8989
spring.application.name=travels
pe=com.alibaba.druid.pool.DruidDataSource
spring.datasource.sql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/travels?characterEncoding=UTF-8汉代陶器
spring.datasource.urname=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:org/hz/travels/mapper/*.xml
#图⽚存储到本地位置
零食导购
upload.dir=E://images
3.⽤户模块
注册模块–验证码
原始验证码的实现较为简单,通过验证码⼯具类⽣成⼀个验证码,通过 ssion.tAttribute(“code”, String());将code设置到ssion域中,当⽤户注册的时候,输⼊的验证码与ssion中的验证码进⾏⽐较即可。
**但是此项⽬由于使⽤的是前后端分离项⽬,前端采⽤vue+axios⽅式,axios底层封装了Ajax请求,但是Ajax请求是XMLHTTPRequest对象发起的⽽不是浏览器,导致每次请求都会⽣成⼀个esion会话,这样当点击注册按钮之后,对⽣成⼀个新的会话,⽽这个新的会话中不存在“code”,所以在⽐对⽤户提交的验证码的时候就会出现异常。**原⽣Ajax的解决⽅法:提供了xhrFields: {withCredentials: true}属性⽤于携带认证信息,即携带上⼀次请求⽣成的Cookie去发出请求,保证了Session的唯⼀性。
但是在axios中暂时知道怎么使⽤,所以此处先临时将验证码设置到了ServletContext对象中。
后端代码如下:
/*
获取验证码,通过map将验证码的ba64编码响应给客户端
*/
@GetMapping("getImage")
public Map<String, String>getImage(HttpServletRequest request)throws IOException {
Map<String, String> result =new HashMap<>();
CreateImageCode createImageCode =new CreateImageCode();
//获取验证码
String curityCode = Code();
//验证码存⼊ssion
String key =new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//⽣成图⽚
BufferedImage image = BuffImg();
//进⾏ba64编码
ByteArrayOutputStream bos =new ByteArrayOutputStream();
ImageIO.write(image,"png", bos);
//进⾏Ba64的⼀个编码
String string = ByteArray());
result.put("key", key);
result.put("image", string);
return result;
}
前端渲染:
动态绑定src
<img :src="src" id="img-vcode" @click="getImage":key="key">
const app =new Vue({
el:"#app",
data:{
ur:{},
code:"",
src:"",
key:"",
},
methods:{
getImage(){//获取验证码
_this =this;
<("localhost:8989/ur/getImage").then((res)=>{
console.log(res.data.key);
//绑定图⽚的src属性。
_this.src ="data:image/png;ba64,"+res.data.image;
_this.key = res.data.key;
});
}
狰狞面目
},
//⽣命周期函数,实例⽣成以后执⾏
created(){
}
});
_this.src = “data:image/png;ba64,”+res.data.image; //解码的时候必须指定前缀_this.key = res.data.key; //这个key是后台设置的ServletContext
created(){
注册模块–保存⽤户
<form action="province/provincelist.html"method="post">
<label>
<div class="label-text">账&emsp;号:</div>
<input type="text"v-model="ur.urname"name="urname">
</label>
<label>
<div class="label-text">密&emsp;码:</div>
<input type="password"v-model="ur.password"name="password">
</label>
<label>
<div class="label-text">邮&emsp;箱:</div>
<input type="text"v-model="ur.email"name="email">
</label>
<img :src="src"id="img-vcode"@click="getImage":key="key">
<label>
<div class="label-text">验证码:</div>
<input type="text"v-model="code"name="vcode" >
</label>
<button type="button"@click="saveUrInfo">提交</button>
<a href="login.html">去登录</a>
</form>
使⽤v-model和this.ur属性进⾏绑定,图⽚的绑定key属性
javacript代码:
const app =new Vue({
el:"#app",
data:{
ur:{},//关联的⽤户对象
code:"",//⽤户输⼊的验证码
src:"",//绑定的src属性
key:"",//后台返回的时间戳key,前台重新提交,根据key判断ServletContext是否存在
},
methods:{
saveUrInfo(){//注册
console.log(this.ur.urname +this.ur.password +ail);
console.de);
if(!this.ur.urname){
alert('⽤户名不能为空');
return;
}
if(!this.ur.password){
alert('密码不能为空');
return;
}
//发送axios
axios.post("localhost:8989/ur/register?code="+de+"&key="+this.key,this.ur).then((res)=>{ console.log(res);
if(res.data.state){
alert(res.data.msg+",点击确定跳转到登录页⾯");
location.href='./login.html';
}el{
alert(res.data.msg);
}
});
}
},
//⽣命周期函数,实例⽣成以后执⾏
created(){
}
});
后端注册代码:
@PostMapping("register")
public Result register(String code, String key,@RequestBody Ur ur, HttpServletRequest request){ Result result =new Result();
//获取ServletContex中存储的验证码
String keyCode =(String) ServletContext().getAttribute(key);
//验证
try{
if(code.equalsIgnoreCa(keyCode)){
//注册⽤户
result.tState(true);
result.tMsg("注册成功");
}el{
throw new RuntimeException("验证码错误");
}
}catch(Exception e){
e.printStackTrace();
//捕获异常信息,并将其设置到响应信息中
result.Message()).tState(fal);
}
return result;
}
4.省份模块
最终效果:
分页展⽰模块:
分页查询后端代码:
@RequestMapping("findByPage")
public Map<String ,Object>findByPage(Integer page,Integer rows){
page = page == null ?1: page;
rows = rows == null ?4: rows;
HashMap<String, Object> map =new HashMap<>();
//分页处理
List<Province> provinces = provinceService.findByPage(page, rows);
//计算总页数
Integer totals = provinceService.findTotals();
Integer totalPage = totals % rows ==0? totals / rows : totals / rows +1;
map.put("provinces", provinces);
map.put("totals", totals);
map.put("totalPage", totalPage);
map.put("page", page);
return map;
}
使⽤map集合返回给前端,其中需要的数据有:
1. page,当前页是第⼏页
2. rows:每页显⽰多少条记录。
3. totals:总共多少条记录
4. totalPage:总共多少页
5. province为返回的省份list集合。
季节风分页查询Service层代码:
@Override
public List<Province>findByPage(Integer page, Integer rows){
//⽐如查询第1页,那么就查询的是limit 0,rows
int start =(page-1)*rows;
return provinceMapper.findByPage(start,rows);
}
<resultMap id="BaResultMap"type="ity.Province">
<id column="id"property="id"jdbcType="INTEGER"/>
<result column="name"property="name"jdbcType="VARCHAR"/>
<result column="tags"property="tags"jdbcType="VARCHAR"/>
<result column="placecounts"property="placecounts"jdbcType="INTEGER"/>
</resultMap>
<lect id="findByPage"resultType="Province">
lect id,name,tags,placecounts
from t_province
order by placecounts
limit #{start},#{rows}
</lect>
前端实现:
html:
<div id="pages">
<!-- 当page -->
<a href="javascript:;"@click="findAll(page-1)"v-if="page>1"class="page"><;上⼀页</a>
四在农家<a class="page"href="javascript:;"v-for="indexpage in totalPage"@click="findAll(indexpage)"v-text="indexpage"></a> <a href="javascript:;"v-if="page<totalPage"@click="findAll(page+1)"class="page">下⼀页></a>
</div>
script代码:
const app =new Vue({
el:"#app",
data:{
provinces:[],
page:1,//第⼀次加载列表默认加载第⼀页数据
rows:2,//指定每页加载两条数据
totalPage:0,//总共多少页
totals:0,//共多少条数据
},
methods:{
//⽤户点击第⼏页,就传这个页码的值去做请求。
findAll(indexpage){//查询所有
if(indexpage){
this.page = indexpage;
}
_this =this;
光彩的意思松柏的特点("localhost:8989/province/findByPage?page="+this.page +"&rows="+ws).then((res)=>{
_this.provinces = res.data.provinces;
_this.page = res.data.page;
_alPage = alPage;
_als = als;
});
}
},
//vue实例化前加载列表
created(){
this.findAll();
}
})