JavaWeb《后端内容:5. 项目实战:书城系统(下篇)》

news/2025/1/11 9:08:33/

目录

1. Cookie了解

Cookie在浏览器和服务器之间的传递

1. 创建Cookie对象 在客户端保存Cookie

2. 设置Cookie的有效时长

3. Cookie的应用

2. kaptcha

3. 注册功能实装

3.1 注册的初步实现

3.2 正则表达式了解

3.3 注册页面的表单验证

3.4 判断用户名是否已经被注册(原生Ajax方式)

1. Ajax

3. VUE和Axios

3.1 Vue入门

0. 定义对象的两种方式 

1 {{}} - 相当于innerText

2 v-bind:attr 绑定属性值

3 v-model 双向绑定

4 v-if , v-else , v-show

5 v-for 迭代

6 v-on 绑定事件

7 其他

8 生命周期

3.2 Axios入门

Axios是Ajax的一个框架,简化Ajax操作

2-2. 客户端向服务器发送JSON格式的数据

4. 使用VUE和Axios改写书城项目

4.1 购物车模块改写


1. Cookie了解

创建一个新的module webmodule16-cookie-kaptcha-js ,添加web支持框架。同时导入tomcat包。

HTTP协议本身是无状态的。单靠HTTP协议本身无法判断一个请求来自于哪一个浏览器,所以也就没法识别用户的身份状态。

Cookie本质

在浏览器端临时存储数据

键值对

键和值都是字符串类型

数据量很小

②Cookie在浏览器和服务器之间的传递

没有Cookie的状态

在服务器端没有创建Cookie并返回的情况下,浏览器端不会保存Cookie信息。双方在请求和响应的过程中也不会携带Cookie的数据。

1. 创建Cookie对象 在客户端保存Cookie

@WebServlet("/cookie01")
public class CookieServlet01 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 1. 创建Cookie对象Cookie cookie = new Cookie("uname", "jim");// 2. 将Cookie对象添加到响应中resp.addCookie(cookie);req.getRequestDispatcher("hello01.html").forward(req, resp);}
}

2. 设置Cookie的有效时长

设置cookie的有效时长是60秒

cookie.setMaxAge(60)   

上网时间长了,本地会保存很多Cookie。对浏览器来说,访问互联网资源时不能每次都把所有Cookie带上。浏览器会使用Cookie的domain和path属性值来和当前访问的地址进行比较,从而决定是否携带这个Cookie

cookie.setDomain(pattern)

cookie.setPath(uri)

3. Cookie的应用

1. 记住用户名和密码十天 setMaxAge(60 * 60 * 24 * 10)

2. 十天免登录

2. kaptcha

1. kaptcha如何使用

添加jar
在web.xml文件中注册KaptchaServlet,并设置验证码图片的相关属性,kaptcha验证码图片的各个属性在常量接口:Constants中。这个可以从jar包的Constants里面看到字段名称,然后相应设置

<?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>KaptchaServlet</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class><init-param><param-name>kaptcha.border.color</param-name><param-value>red</param-value></init-param><init-param><param-name>kaptcha.textproducer.char.string</param-name><param-value>abcdefg</param-value></init-param></servlet><servlet-mapping><servlet-name>KaptchaServlet</servlet-name><url-pattern>/kaptcha.jpg</url-pattern></servlet-mapping></web-app>

在html页面上编写一个img标签,然后设置src等于KaptchaServlet对应的url-pattern。此时我们访问静态页面的html,即可显示动态变化的验证码图片。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img src="kaptcha.jpg" alt="">
</body>
</html>

2. KaptchaServlet在生成验证码图片时,会同时将验证码信息保存到session中,key在Constants也有,是KAPTCHA_SESSION_KEY

因此,我们在注册请求时,首先将用户文本框中输入的验证码值和session中保存的值进行比较,相等,则进行注册,我们每次访问它其实它会动态变化,并覆盖放入session中,我们可以写一个Servlet去检验一下

@WebServlet("/kaptcha01")
public class KaptchaServletDemo01 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();Object obj = session.getAttribute("KAPTCHA_SESSION_KEY");System.out.println("obj = " + obj);}
}

3. 注册功能实装

3.1 注册的初步实现

现在我们创立新的模块,然后导入kaptcha包,同时把这个最外层的用户验证过滤器注释掉,方便我们先把注册功能实装。

因为我们的登录页面放在user文件下的regist.html,所以tomcat的默认访问主页改为

http://localhost:8080/webmodule16/page.do?operate=page&page=user/regist

然后改写静态html,加入Thymeleaf。首先把路径都改为thymeleaf的,然后把表单的action,改为和之前login页面相同的user.do,然后method因为是表单,应该写为post,而因为是post没法直接带过去operate,所以写一个input的隐藏域,name=operate,而value=regist。(可以直接复制之前的login.html下的这部分),而kaptchaServlet的配置,放在web.xml下,我们就能在前端配置验证码图片的地方写入url-pattern

    <servlet><servlet-name>KaptchaServlet</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class><init-param><param-name>kaptcha.image.width</param-name><param-value>120</param-value></init-param><init-param><param-name>kaptcha.image.height</param-name><param-value>50</param-value></init-param></servlet><servlet-mapping><servlet-name>KaptchaServlet</servlet-name><url-pattern>/kaptcha.jpg</url-pattern></servlet-mapping>
                <div><label>验证码:</label><div class="verify"><input type="text" placeholder=""/><img th:src="@{/kaptcha.jpg}" alt=""/></div></div>

为了真的完成注册功能,我们就需要给UserDAO和UserService层写添加用户的方法了,这里先不考虑用户名,邮箱重复的问题。

public interface UserDAO {public User getUser(String uname, String pwd);public void addUser(User user);
}
-------------------------------------------------------------------------------------
public class UserDAOImpl extends BaseDao implements UserDAO {@Overridepublic User getUser(String uname, String pwd) {---}@Overridepublic void addUser(User user) {String sql = "INSERT INTO t_user VALUES (0, ?, ?, ?, 0);";try {executeUpdate(sql, user.getUname(), user.getPwd(), user.getEmail());} catch (SQLException e) {e.printStackTrace();throw new RuntimeException("UserDAO.addUser出错了");}}
}
-------------------------------------------------------------------------------------
public interface UserService {public User login(String uname, String pwd);public void regist(User user);
}
-------------------------------------------------------------------------------------
public class UserServiceImpl implements UserService {private UserDAO userDAO;@Overridepublic User login(String uname, String pwd) {---}@Overridepublic void regist(User user) {userDAO.addUser(user);}
}

这里UserController里写regist方法,形参应该是从注册页面获取,当然为了完成验证码比较,需要写HttpSession,除了账号密码邮箱外,还应该获取验证码的Code,这里我们别忘了把输入验证码的input地方写上相应参数value=verifyCode,也别忘了给用户名密码邮箱的input表单写value值。

                    <label>验证码:</label><div class="verify"><input type="text" name="verifyCode" placeholder=""/><img th:src="@{/kaptcha.jpg}" alt=""/></div>

这里老师其实为了让输错验证码不出现直接跳转没有提示,使用response回应一个流写了js代码,让它提示密码错误。主要因为myssm这里已经封装jar包,本来可以return null,然后改写DispatcherServlet那里,如果为null就return,或者是返回空字符串,总之为了实现我们写的js方法跳转。因为已经封装jar包了,这里就不这么改了。

public class UserController {private UserService userService = null;private CartItemService cartItemService = null;public String login(String uname, String pwd, HttpSession session) {User user = userService.login(uname, pwd);if (user != null) {Cart cart = cartItemService.getCart(user);user.setCart(cart);session.setAttribute("currUser", user);return "redirect:book.do";}return "user/login";}public String regist(String uname, String pwd, String email, String verifyCode,HttpSession session, HttpServletResponse resp) throws IOException {Object kaptchaCodeObj = session.getAttribute("KAPTCHA_SESSION_KEY");if (kaptchaCodeObj == null || !kaptchaCodeObj.equals(verifyCode)){resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");PrintWriter out = resp.getWriter();//out.println("<script language='javascript'>alert('验证码不正确!');window.location.href='page.do?operate=page&page=user/regist';</script>");out.println("<script language='javascript'>alert('验证码不正确!');</script>");//return "user/regist";return "user/regist";} else{if (verifyCode.equals(kaptchaCodeObj)){userService.regist(new User(uname, pwd, email));return "user/login";}}return "user/login";}
}

3.2 正则表达式了解

Road 2 Codinghttps://www.r2coding.com/#/README?id=%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F1)正则表达式的使用三步骤:
1. 定义正则表达式对象
    正则表达式定义有两个方式:
    1) 对象形式
    var reg = new RegExp("abc")
    2) 直接量形式
    var reg = /abc/;

test方法是只要存在一个满足要求的,就返回true

    <script language="JavaScript">var reg1 = new RegExp("abc");var reg2 = /abd/;var str = "abcdefg";var flag1 = reg1.test(str);var flag2 = reg2.test(str);console.log(flag1);console.log(flag2);</script>

3) 匹配模式:

- g 全局匹配 global

    <script language="JavaScript">var reg1 = /o/g;var reg2 = /o/;var str = "abcoabco";str1 = str.replace(reg1, "_");str2 = str.replace(reg2, "_");console.log(str1);console.log(str2);</script>

- i 忽略大小写匹配 ignore

- m 多行匹配

- gim这三个可以组合使用,不区分先后顺序

例如: var reg = /abc/gim , var reg = new RegExp("abc","gim");

2. 定义待校验的字符串

3. 校验

2)元字符 和 [ ]表示集合

    

    <script language="JavaScript">var reg = /\w/gim;var str = "java%s\nc@ript";str = str.replace(reg, "A");console.log(str);</script>

   3) 出现的次数

    <script language="JavaScript">var reg = /[a]{2}/gim;var str = "aaaaaaaaaaaajava%s\nc@ript";str = str.replace(reg, "#");document.write(str);</script>

3.3 注册页面的表单验证

原本的注册页面html

        <form th:action="@{/user.do}" method="post"><input type="hidden" name="operate" value="regist"><div class="form-item"><div><label>用户名称:</label><input type="text" name="uname" value="王志伟" placeholder="请输入用户名"/></div><span class="errMess">用户名应为6~16位数组和字母组成</span></div><div class="form-item"><div><label>用户密码:</label><input type="password" name="pwd" value="ok" placeholder="请输入密码"/></div><span class="errMess">密码的长度至少为8位</span></div><div class="form-item"><div><label>确认密码:</label><input type="password" name="pwd" value="ok" placeholder="请输入确认密码"/></div><span class="errMess">密码两次输入不一致</span></div><div class="form-item"><div><label>用户邮箱:</label><input type="text" name="email" value="wang@125.com" placeholder="请输入邮箱"/></div><span class="errMess">请输入正确的邮箱格式</span></div><div class="form-item"><div><label>验证码:</label><div class="verify"><input type="text" name="verifyCode" placeholder=""/><img th:src="@{/kaptcha.jpg}" alt=""/></div></div><span class="errMess">请输入正确的验证码</span></div><button class="btn">注册</button></form>

<form>有一个事件 onsubmit 
        οnsubmit="return false" , 那么表单点击提交按钮时不会提交
        οnsubmit="return true" ,  那么表单点击提交按钮时会提交

我们希望表单发送之前能对表单的数据进行校验,如果不满足会显示我们的提示span,如用户名不能为空等。其次要校验满足条件才能提交表单,这里我们就写一个preRegist()的js方法,来完成表单验证。 

<script language="JavaScript" th:src="@{/static/script/regist.js}"></script>

获取文档中某一个节点的方式
DOM:Document
var unameTxt = document.getElementById("unameTxt");
BOM:Browser
document.forms[0].uname

我们给输入的表单的id都叫对应的name值 + Txt 的字符名称,而输入表单如果出错显示的span的id设置为对应name值 + Span 的字符名称。

function $(id){return document.getElementById(id);
}function preRigist(){var unameTxt = $("unameTxt");var unameReg = /^[a-zA-Z\d]{6, 16}$/;var unameSpan = $("unameSpan");if (!unameReg.test(unameTxt)){unameSpan.style.visibility = "visible";return false;}else{unameSpan.style.visibility = "hidden";}return true;
}
            <div class="form-item"><div><label>用户名称:</label><input type="text" id="unameTxt" name="uname" value="王志伟" placeholder="请输入用户名"/></div><span class="errMess" id="unameSpan" >用户名应为6~16位数组和字母组成</span></div>

3.4 判断用户名是否已经被注册(原生Ajax方式)

1. Ajax

Asynchronous Javascript And XML(异步JavaScript和XML)

第一步: 客户端发送异步请求;并绑定对结果处理的回调函数

1) <input type="text" name="uname" οnblur="ckUname()"/>             onblur:失去焦点的事件

<input type="text" id="unameTxt" name="uname" value="王志伟" onblur="ckUname(this.value)" placeholder="请输入用户名"/>

2) 定义ckUname方法

function ckUname(uname) {createXMLHttpRequest();var url = "user.do?operate=ckUname&uname=" + uname;xmlHttpRequest.open("GET", url, true);//设置回调函数xmlHttpRequest.onreadystatechange = ckUnameCB;//发送请求xmlHttpRequest.send();
}

创建XMLHttpRequest对象

//如果想要发送异步请求,我们需要一个关键的对象 XMLHttpRequest
var xmlHttpRequest ;function createXMLHttpRequest(){if(window.XMLHttpRequest){//符合DOM2标准的浏览器 ,xmlHttpRequest的创建方式xmlHttpRequest = new XMLHttpRequest() ;}else if(window.ActiveXObject){//IE浏览器try{xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");}catch (e) {xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP")}}
}

XMLHttpRequest对象操作步骤:
        open(url,"GET",true)
        onreadyStateChange 设置回调
        send() 发送请求
在回调函数中需要判断XMLHttpRequest对象的状态:
        readyState(0-4) , status(200)

下面是完整的代码,事实上这里应该是只写了if判断条件部分,后续写完服务器端给客户端发送数据再补充相应的部分。

function ckUnameCB() {if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {//xmlHttpRequest.responseText 表示 服务器端响应给我的文本内容//alert(xmlHttpRequest.responseText);var responseText = xmlHttpRequest.responseText;// {'uname':'1'}//alert(responseText);if (responseText == "{'uname':'1'}") {alert("用户名已经被注册!");} else {alert("用户名可以注册!");}}
}

第二步:服务器端做校验,然后将校验结果响应给客户端

需要我们给服务器端的userController写相应的ckUname方法,我们要做的是用户名验证,我们之前的登录验证需要从DAO层封装查询账号密码相同的User,这次的用户名验证需要看的是用户名是否重复,所以先去给DAO以及Service层写相应的方法。

public interface UserDAO {public User getUser(String uname, String pwd);public void addUser(User user);public User getUser(String uname);
}
-------------------------------------------------------------------------------------
public class UserDAOImpl extends BaseDao implements UserDAO {@Overridepublic User getUser(String uname, String pwd) {---}@Overridepublic void addUser(User user) {---}@Overridepublic User getUser(String uname) {String sql = "SELECT * FROM t_user WHERE uname = ?;";try {List<User> users = executeQuery(User.class, sql, uname);if (users.size() > 0) {return users.get(0);}} catch (Exception e) {e.printStackTrace();throw new RuntimeException("UserDAO.getUser出错了");}return null;}
}
-------------------------------------------------------------------------------------
public interface UserService {public User login(String uname, String pwd);public void regist(User user);public void getUser(String uname);
}
-------------------------------------------------------------------------------------
public class UserServiceImpl implements UserService {private UserDAO userDAO;@Overridepublic User login(String uname, String pwd) {---}@Overridepublic void regist(User user) {---}@Overridepublic void getUser(String uname) {userDAO.getUser(uname);}
}

然后写UserController,这里其实需要改DispatcherServlet,因为我们之前只做了redirect前缀的判断处理,这里涉及到Ajax需要给它特别处理

public class UserController {private UserService userService = null;private CartItemService cartItemService = null;public String login(String uname, String pwd, HttpSession session) {---}public String regist(String uname, String pwd, String email, String verifyCode,HttpSession session, HttpServletResponse resp) throws IOException {---}String ckUname(String uname){User user = userService.getUser(uname);if (user==null){//用户名已经被占用,不可以注册//这里最方便的是改DispatcherServlet,把带有ajax开头的地方专门处理//return "ajax:1";return "json:{'uname':'1}";}else{//用户名可以注册return "json:{'uname':'0}";//return "ajax:0";}}
}

这里我们直接把myssm1.0的jar包去除,然后复制上一个项目的myssm部分,然后改写DispatcherServlet的代码。这里else if的部分是新加入的。

                    // 3. 视图处理String methodReturnStr = (String) returnObj;if (methodReturnStr.startsWith("redirect:")) {   //比如 "redirect:fruit.do"String redirectStr = methodReturnStr.substring("redirect:".length());resp.sendRedirect(redirectStr);// 发送json数据}else if(methodReturnStr.startsWith("json:")){String jsonStr = methodReturnStr.substring("json:".length());PrintWriter out = resp.getWriter();out.println(jsonStr);out.flush();}else {super.processTemplate(methodReturnStr, req, resp); //比如 "edit" "index"}}

既然给客户端发送了数据,就需要在客户端接受,这里接着去写之前的ajax的js代码

function ckUnameCB() {if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {//xmlHttpRequest.responseText 表示 服务器端响应给我的文本内容//alert(xmlHttpRequest.responseText);var responseText = xmlHttpRequest.responseText;// {'uname':'1'}//alert(responseText);if (responseText == "{'uname':'1'}") {alert("用户名已经被注册!");} else {alert("用户名可以注册!");}}
}

 然后运行,设置断点看看有没有出错 

在Controller这里也设置断点 

这里发现已经完成功能,彻底实现了对用户名的校验和异步的ajax,至此完成用户名校验功能。 

Ajax : 异步的JavaScript and XML
    目的: 用来发送异步的请求,然后当服务器给我响应的时候再进行回调操作
    好处: 提高用户体验;局部刷新:降低服务器负担、减轻浏览器压力、减轻网络带宽压力
    开发步骤:
      1) 创建XMLHttpRequest
      2) 调用open进行设置:"GET" , URL , true
      3) 绑定状态改变时执行的回调函数 - onreadystatechange
      4) 发送请求 - send()
      5) 编写回调函数,在回调函数中,我们只对XMLHttpRequest的readystate为4的时候感兴趣
                                我们只对XMLHttpRequest的status为200的时候感兴趣

    0: (Uninitialized) the send( ) method has not yet been invoked.
    1: (Loading) the send( ) method has been invoked, request in progress.
    2: (Loaded) the send( ) method has completed, entire response received.
    3: (Interactive) the response is being parsed.
    4: (Completed) the response has been parsed, is ready for harvesting.

    0 - (未初始化)还没有调用send()方法
    1 - (载入)已调用send()方法,正在发送请求
    2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
    3 - (交互)正在解析响应内容
    4 - (完成)响应内容解析完成,可以在客户端调用了 

3. VUE和Axios

3.1 Vue入门

这里新建了项目,然后创建了一个新的html文件,然后把vue和Axios的js文件放入

指明vue路径

<script language="JavaScript" src="script/vue.js"></script>

0. 定义对象的两种方式 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">function hello(){person.sayHello();}//定义js对象方式一:/*var person = new Object();person.pid = "p001";person.pname="jim";person.sayHello = function(){alert("HELLO world");}*///定义js对象方式二:var person = {"pid":"p001","pname":"jim","sayHello":function(){alert("HELLO world");}};window.onload=function(){var vue = new Vue({});}</script>
</head>
<body><div id="div0"><span>HELLO</span><input type="button" value="打招呼" onclick="hello()"/></div>
</body>
</html>

1 {{}} - 相当于innerText

2 v-bind:attr 绑定属性值

例如,v-bind:value - 绑定value值
简写:    :value

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{msg:"hello!!!",uname:"鸠摩智"}});}</script>
</head>
<body><div id="div0"><span>{{msg}}</span><!-- v-bind:value表示绑定value属性 , v-bind可以省略,也就是 :value --><!--<input type="text" v-bind:value="uname"/>--><input type="text" :value="uname"/></div>
</body>
</html>

3 v-model 双向绑定

v-model:value   , 简写  v-model

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{msg:"hello!!!"}});}</script>
</head>
<body><div id="div0"><span>{{msg}}</span><br/><!--v-model指的是双向绑定,也就是说之前的v-bind是通过msg这个变量的值来控制input输入框现在 v-model 不仅msg来控制input输入框,反过来,input输入框的内容也会改变msg的值--><!--<input type="text" v-model:value="msg"/>--><!-- v-model:value 中 :value可以省略,直接写成v-model --><!-- trim可以去除首尾空格 --><input type="text" v-model.trim="msg"/></div>
</body>
</html>

4 v-if , v-else , v-show

v-if和v-else之间不能有其他的节点
v-show是通过样式表display来控制节点是否显示

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{num:2}});}</script>
</head>
<body><div id="div0"><input type="text" v-model="num"/><!-- v-if和v-else之间不可以插入其他节点 --><!--<div v-if="num%2==0" style="width:200px;height:200px;background-color: chartreuse;">&nbsp;</div>--><!--<br/>--><!--<div v-else="num%2==0" style="width:200px;height:200px;background-color: coral">&nbsp;</div>--><!-- v-show --><!-- v-show是通过display属性来控制这个div是否显示 --><div v-show="num%2==0" style="width:200px;height:200px;background-color:blueviolet;">&nbsp;</div></div>
</body>
</html>

5 v-for 迭代

v-for={fruit in fruitList}

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{fruitList:[{fname:"苹果",price:5,fcount:100,remark:"苹果很好吃"},{fname:"菠萝",price:3,fcount:120,remark:"菠萝很好吃"},{fname:"香蕉",price:4,fcount:50,remark:"香蕉很好吃"},{fname:"西瓜",price:6,fcount:100,remark:"西瓜很好吃"}]}});}</script>
</head>
<body><div id="div0"><table border="1" width="400" cellpadding="4" cellspacing="0"><tr><th>名称</th><th>单价</th><th>库存</th><th>备注</th></tr><!-- v-for表示迭代 --><tr align="center" v-for="fruit in fruitList"><td>{{fruit.fname}}</td><td>{{fruit.price}}</td><td>{{fruit.fcount}}</td><td>{{fruit.remark}}</td></tr></table></div>
</body>
</html>

6 v-on 绑定事件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{msg:"hello world!"},methods:{myReverse:function(){this.msg = this.msg.split("").reverse().join("");}}});}</script>
</head>
<body><div id="div0"><span>{{msg}}</span><br/><!-- v-on:click 表示绑定点击事件 --><!-- v-on可以省略,变成 @click --><!--<input type="button" value="反转" v-on:click="myReverse"/>--><input type="button" value="反转" @click="myReverse"/></div>
</body>
</html>

7 其他

trim:去除首尾空格   split()   join()

watch表示侦听属性

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{num1:1,num2:2,num3:0},watch:{//侦听属性num1和num2//当num1的值有改动时,那么需要调用后面定义的方法 , newValue指的是num1的新值num1:function(newValue){this.num3 = parseInt(newValue) + parseInt(this.num2);},num2:function(newValue){this.num3 = parseInt(this.num1) + parseInt(newValue) ;}}});}</script>
</head>
<body><div id="div0"><input type="text" v-model="num1" size="2"/>+<input type="text" v-model="num2" size="2"/>=<span>{{num3}}</span></div>
</body>
</html>

8 生命周期

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{msg:1},methods:{changeMsg:function(){this.msg = this.msg + 1 ;}},/*vue对象创建之前*/beforeCreate:function(){console.log("beforeCreate:vue对象创建之前---------------");console.log("msg:"+this.msg);},/*vue对象创建之后*/created:function(){console.log("created:vue对象创建之后---------------");console.log("msg:"+this.msg);},/*数据装载之前*/beforeMount:function(){console.log("beforeMount:数据装载之前---------------");console.log("span:"+document.getElementById("span").innerText);},/*数据装载之后*/mounted:function(){console.log("mounted:数据装载之后---------------");console.log("span:"+document.getElementById("span").innerText);},beforeUpdate:function(){console.log("beforeUpdate:数据更新之前---------------");console.log("msg:"+this.msg);console.log("span:"+document.getElementById("span").innerText);},updated:function(){console.log("Updated:数据更新之后---------------");console.log("msg:"+this.msg);console.log("span:"+document.getElementById("span").innerText);}});}</script>
</head>
<body><div id="div0"><span id="span">{{msg}}</span><br/><input type="button" value="改变msg的值" @click="changeMsg"/></div>
</body>
</html>

3.2 Axios入门

Axios是Ajax的一个框架,简化Ajax操作

Axios执行Ajax操作的步骤:
   1. 添加并引入axios的js文件   2-1. 客户端向服务器端异步发送普通参数值
基本格式
: axios().then().catch()
示例:

     axios({method:"POST",url:"....",params:{uname:"lina",pwd:"ok"}}).then(function(value){})          //成功响应时执行的回调        value.data可以获取到服务器响应内容.catch(function(reason){});       //有异常时执行的回调          reason.response.data可以获取到响应的内容//                           reason.message / reason.stack 可以查看错误的信息
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>01.演示Axios发送普通的参数值给服务器端</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript" src="script/axios.min.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{uname:"lina",pwd:"ok"},methods:{axios01:function(){axios({method:"POST",url:"axios01.do",params:{uname:vue.uname,pwd:vue.pwd}}).then(function (value) {console.log(value);}).catch(function (reason) {console.log(reason);});}}});}</script>
</head>
<body><div id="div0">uname:<input type="text" v-model="uname"/><br/>pwd:<input type="text" v-model="pwd"/><br/><input type="button" @click="axios01" value="发送一个带普通请求参数值的异步请求"/></div>
</body>
</html>
@WebServlet("/axios01.do")
public class Axios01Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");String uname = request.getParameter("uname");String pwd = request.getParameter("pwd");System.out.println("uname = " + uname);System.out.println("pwd = " + pwd);response.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.write(uname+"_"+pwd);throw new NullPointerException("这里故意抛出一个空指针异常....");}
}

2-2. 客户端向服务器发送JSON格式的数据

什么是JSON

JSON是一种数据格式
XML也是一种数据格式
XML格式表示两个学员信息的代码如下

      <students><student sid="s001"><sname>jim</sname><age>18</age></student><student sid="s002"><sname>tom</sname><age>19</age></student></students>

JSON格式表示两个学员信息的代码如下:
      [{sid:"s001",age:18},{sid:"s002",age:19}]
JSON表达数据更简洁,更能够节约网络带宽
客户端发送JSON格式的数据给服务器端
1) 客户端中params需要修改成:  data:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>02.演示Axios发送JSON格式的参数值给服务器端</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript" src="script/axios.min.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{uname:"lina",pwd:"ok"},methods:{axios02:function(){axios({method:"POST",url:"axios02.do",data:{uname:vue.uname,pwd:vue.pwd}}).then(function (value) {console.log(value);}).catch(function (reason) {console.log(reason);});}}});}</script>
</head>
<body><div id="div0">uname:<input type="text" v-model="uname"/><br/>pwd:<input type="text" v-model="pwd"/><br/><input type="button" @click="axios02" value="发送JSON格式的参数值的异步请求"/></div>
</body>
</html>

2) 服务器获取参数值不再是 request.getParameter()...
而是:

       StringBuffer stringBuffer = new StringBuffer("");BufferedReader bufferedReader = request.getReader();String str = null ;while((str=bufferedReader.readLine())!=null){stringBuffer.append(str);}str = stringBuffer.toString() ;

3) 我们会发现 str的内容如下:
       {"uname":"lina","pwd":"ok"}

服务器端给客户端响应JSON格式的字符串,然后客户端需要将字符串转化成js Object

这里需要用第三方jar包Gson

Gson有两个API,可以通过 new Gson()生成Gson对象,然后调用它们

1.fromJson(string,T) 将字符串转化成java object

2.toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端

将前端发送的json转化为java Object

Pojo对象

public class User {private String uname ;private String pwd ;public User(){}public User(String uname, String pwd) {this.uname = uname;this.pwd = pwd;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"uname='" + uname + '\'' +", pwd='" + pwd + '\'' +'}';}
}

 axiosServlet

@WebServlet("/axios02.do")
public class Axios02Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {StringBuffer stringBuffer = new StringBuffer("");BufferedReader bufferedReader = request.getReader();String str = null ;while((str=bufferedReader.readLine())!=null){stringBuffer.append(str);}str = stringBuffer.toString() ;//已知 String//需要转化成 Java ObjectGson gson = new Gson();//Gson有两个API//1.fromJson(string,T) 将字符串转化成java object//2.toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端User user = gson.fromJson(str, User.class);System.out.println(user);}
}

前端页面 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>02.演示Axios发送JSON格式的参数值给服务器端</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript" src="script/axios.min.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{uname:"lina",pwd:"ok"},methods:{axios02:function(){axios({method:"POST",url:"axios02.do",data:{uname:vue.uname,pwd:vue.pwd}}).then(function (value) {console.log(value);}).catch(function (reason) {console.log(reason);});}}});}</script>
</head>
<body><div id="div0">uname:<input type="text" v-model="uname"/><br/>pwd:<input type="text" v-model="pwd"/><br/><input type="button" @click="axios02" value="发送JSON格式的参数值的异步请求"/></div>
</body>
</html>

 将后端的java Object转化为json发送给前端

axiosServlet

@WebServlet("/axios03.do")
public class Axios03Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {StringBuffer stringBuffer = new StringBuffer("");BufferedReader bufferedReader = request.getReader();String str = null ;while((str=bufferedReader.readLine())!=null){stringBuffer.append(str);}str = stringBuffer.toString() ;//已知 String//需要转化成 Java ObjectGson gson = new Gson();//Gson有两个API//1.fromJson(string,T) 将字符串转化成java object//2.toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端User user = gson.fromJson(str, User.class);user.setUname("鸠摩智");user.setPwd("123456");//假设user是从数据库查询出来的,现在需要将其转化成json格式的字符串,然后响应给客户端String userJsonStr = gson.toJson(user);response.setCharacterEncoding("UTF-8");//MIME-TYPEresponse.setContentType("application/json;charset=utf-8");response.getWriter().write(userJsonStr);}
}

前端页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>03.演示Axios发送异步请求给服务器端,服务器响应json格式的数据给客户端</title><script language="JavaScript" src="script/vue.js"></script><script language="JavaScript" src="script/axios.min.js"></script><script language="JavaScript">window.onload=function(){var vue = new Vue({"el":"#div0",data:{uname:"lina",pwd:"ok"},methods:{axios03:function(){axios({method:"POST",url:"axios03.do",data:{uname:vue.uname,pwd:vue.pwd}}).then(function (value) {var data = value.data;// data对应的数据:// {uname:"鸠摩智",pwd:"ok"}vue.uname=data.uname;vue.pwd=data.pwd;//此处value中的data返回的是 js object,因此可以直接点出属性//如果我们获取的是一个字符串:  "{uname:\"鸠摩智\",pwd:\"ok\"}"//js语言中 也有字符串和js对象之间互转的API//string JSON.stringify(object)     object->string//object JSON.parse(string)         string->object}).catch(function (reason) {console.log(reason);});}}});}</script>
</head>
<body><div id="div0">uname:<input type="text" v-model="uname"/><br/>pwd:<input type="text" v-model="pwd"/><br/><input type="button" @click="axios03" value="服务器响应json格式的数据给客户端"/></div>
</body>
</html>

js语言中 也有字符串和js对象之间互转的API

string JSON.stringify(object) object->string

object JSON.parse(string) string->object

这里展示一下JS里面转化字符串和Object

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>04.JS中的字符串和Object之间互转的API</title><script language="JavaScript">function hello01(){/*//1. js string - > js objectvar str = "{\"uname\":\"lina\",\"age\":20}";var user = JSON.parse(str);alert(typeof user);alert(user.uname+"_"+user.age);*///2. js object -> js stringvar user = {"uname":"lina","age":99};alert(typeof user);var userStr = JSON.stringify(user);alert(typeof userStr);alert(userStr);}</script>
</head>
<body><div id="div0"><input type="button" value="确定" onclick="hello01()"/></div>
</body>
</html>

AxiosServlet 

@WebServlet("/axios03.do")
public class Axios03Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {StringBuffer stringBuffer = new StringBuffer("");BufferedReader bufferedReader = request.getReader();String str = null ;while((str=bufferedReader.readLine())!=null){stringBuffer.append(str);}str = stringBuffer.toString() ;//已知 String//需要转化成 Java ObjectGson gson = new Gson();//Gson有两个API//1.fromJson(string,T) 将字符串转化成java object//2.toJson(java Object) 将java object转化成json字符串,这样才能响应给客户端User user = gson.fromJson(str, User.class);user.setUname("鸠摩智");user.setPwd("123456");//假设user是从数据库查询出来的,现在需要将其转化成json格式的字符串,然后响应给客户端String userJsonStr = gson.toJson(user);response.setCharacterEncoding("UTF-8");//MIME-TYPEresponse.setContentType("application/json;charset=utf-8");response.getWriter().write(userJsonStr);}
}

4. 使用VUE和Axios改写书城项目

4.1 购物车模块改写

复制之前的书城项目为新模块,然后导入相应的包,添加框架支持。

这里改造一下DispatcherServlet,需要在返回字符串为空的时候,直接return,不渲染页面。

                    // 2. controller组件中的方法调用method.setAccessible(true);Object returnObj = method.invoke(controllerBeanObj, parameterValues); // “2”// 3. 视图处理String methodReturnStr = (String) returnObj;if (StringUtil.isEmpty(methodReturnStr)) {return;}if (methodReturnStr.startsWith("redirect:")) {   //比如 "redirect:fruit.do"String redirectStr = methodReturnStr.substring("redirect:".length());resp.sendRedirect(redirectStr);// 发送json数据}else if(methodReturnStr.startsWith("json:")){String jsonStr = methodReturnStr.substring("json:".length());PrintWriter out = resp.getWriter();out.print(jsonStr);out.flush();}else {super.processTemplate(methodReturnStr, req, resp); //比如 "edit" "index"}}

我们此前客户端发送请求是通过DispatcherServlet分配,发给Controller,然后返回给Thymeleaf渲染,现在是直接访问html,然后通过axios发送ajax请求,然后通过vue实时的渲染。

这里我们以前访问购物车是直接访问购物车的Controller,然后默认使用index方法。

                <a th:href="@{/cart.do}" class="cart iconfont icon-gouwuche ">购物车<div class="cart-num" th:text="${session.currUser.cart.getTotalCount()}">3</div></a>

现在我们想改成访问html,先改成这个样子,虽然还是经过thymeleaf渲染,但是我们一会会把前端的页面部分的thymeleaf语法都去除,css路径,图片路径这些可以先不改。

                <a th:href="@{/page.do(operate='page', page='cart/cart')}" class="cart iconfont icon-gouwuche ">购物车<div class="cart-num" th:text="${session.currUser.cart.getTotalCount()}">3</div></a>

以前我们购物车的数据是经过CartController的index方法,然后把Session中用户的购物车列表通过thymeleaf打印,现在我们不用这种方法,先给图书的div写id,记得引入vue和axios,文件也复制过来。

<script language="JavaScript" th:src="@{/static/script/cart.js}"></script>

因为我们之前这个页面绑定html文件在cart.js,我们就在这里把vue添加上去。id写刚刚书写的#cart_div,而data暂时不填,先暂时写一个beforemount,然后methods里面写axios,method这里我们先写POST,而url我们写cart.do,通过.then在控制台输出参数验证是否做到了数据的获取,同时我们在数据装载的时候去调用一下getCart方法

function editCart(cartItemId, buyCount) {window.location.href = 'cart.do?operate=editCart&cartItemId=' + cartItemId + '&buyCount=' + buyCount;
}window.onload = function () {var vue = new Vue({el: "#cart_div",data: {},methods: {getCart: function () {axios({method:"POST",url: "cart.do",params: {operate:"cartInfo",}}).then(function (value) {console.log(value.data);}).catch(function (reason) {});}},mounted:function () {this.getCart();}});
}

此前我们是index方法,直接从session获取数据,没有别的参数,这里为了展示axios传参,我们干脆直接写个新的方法cartInfo,这样就可以让axios这里写参数。

public class CartController {private CartItemService cartItemService;public String index(HttpSession session){User user = (User) session.getAttribute("currUser");Cart cart = cartItemService.getCart(user);user.setCart(cart);session.setAttribute("currUser", user);return "cart/cart";}public String cartInfo(HttpSession session){User user = (User) session.getAttribute("currUser");Cart cart = cartItemService.getCart(user);Gson gson = new Gson();String cartJsonStr = gson.toJson(cart);return "json:" + cartJsonStr;}public String addCart(Integer bookId, HttpSession session) {----}public String editCart(Integer cartItemId, Integer buyCount) {----}
}

我们在这个地方设置断点,看看能不能进入这个方法 

发现能进去,然后看axios回调函数返回的是什么数据,事实上这里data就是一个购物车,购物车有cartItemMap这个属性 

那么我们就干脆在data中写一个cart数据类型,然后让回调函数返回的值赋值给这个类型的变量,这里一会用vue,一会用this,是因为在axios中的this是axios对象,而后面的mounted:function ()是vue中的,this就是vue对象。

window.onload = function () {var vue = new Vue({el: "#cart_div",data: {cart:{}},methods: {getCart: function () {axios({method:"POST",url: "cart.do",params: {operate:"cartInfo",}}).then(function (value) {var cart = value.data;vue.cart = cart;}).catch(function (reason) {});}},mounted:function () {this.getCart();}});
}

 然后我们就能把之前thymeleaf改造的前端代码,改写为vue的,这里使用vue的for迭代cartItemMap,其实会出现一个问题,图片返回的路径是project下的直接的路径,但是我们实际放在static下的upload里面,需要以字符串拼接的形式返回。

改造前:

        <table><thead><tr><th>图片</th><th>商品名称</th><th>数量</th><th>单价</th><th>金额</th><th>操作</th></tr></thead><tbody><tr th:each="cartItem : ${session.currUser.getCart().getCartItemMap().values()}"><td><img th:src="@{|/static/uploads/${cartItem.getBook().bookImg}|}" alt=""/></td><td th:text="${cartItem.getBook().bookName}">活着</td><td><span class="count" th:onclick="|editCart(${cartItem.id}, ${cartItem.buyCount - 1})|">-</span><input class="count-num" type="text" th:value="${cartItem.buyCount}"/><span class="count" th:onclick="|editCart(${cartItem.id}, ${cartItem.buyCount + 1})|">+</span></td><td th:text="${cartItem.getBook().price}">36.8</td><td th:text="${cartItem.xj}">36.8</td><td><a href="">删除</a></td></tr></tbody></table>

改造后 

        <table><thead><tr><th>图片</th><th>商品名称</th><th>数量</th><th>单价</th><th>金额</th><th>操作</th></tr></thead><tbody><tr v-for="cartItem in cart.cartItemMap"><td><img v-bind:src="'static/uploads/'+cartItem.book.bookImg" alt="" /></td><td>{{cartItem.book.bookName}}</td><td><span class="count" @click="editCart(cartItem.id,cartItem.buyCount-1)">-</span><input class="count-num" type="text" value="1" v-bind:value="cartItem.buyCount"/><span class="count" @click="editCart(cartItem.id,cartItem.buyCount+1)">+</span></td><td>{{cartItem.book.price}}</td><td>{{cartItem.xj}}</td><td><a href="">删除</a></td></tr></tbody></table>

另外,我们返回的中文发现是乱码,这里其实因为我们之前设置的字符过滤器,在doFilter里面只给request设置了字符编码,没有给response设置,我们添加一下即可。

@WebFilter(urlPatterns = {"*.do"},initParams = {@WebInitParam(name = "encoding", value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {private String encoding = "UTF-8";@Overridepublic void init(FilterConfig filterConfig) throws ServletException {String encodingStr = filterConfig.getInitParameter("encoding");if (StringUtil.isNotEmpty(encodingStr)) {encoding = encodingStr;}}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {((HttpServletRequest)servletRequest).setCharacterEncoding(encoding);((HttpServletResponse)servletResponse).setCharacterEncoding(encoding);filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

当然如果不想改这部分也可以在返回json数据的时候提前在DispatcherServlet里设置。

                    // 2. controller组件中的方法调用method.setAccessible(true);Object returnObj = method.invoke(controllerBeanObj, parameterValues); // “2”// 3. 视图处理String methodReturnStr = (String) returnObj;if (StringUtil.isEmpty(methodReturnStr)) {return;}if (methodReturnStr.startsWith("redirect:")) {   //比如 "redirect:fruit.do"String redirectStr = methodReturnStr.substring("redirect:".length());resp.sendRedirect(redirectStr);// 发送json数据}else if(methodReturnStr.startsWith("json:")){resp.setCharacterEncoding("UTF-8");resp.setContentType("application/json,charset=UTF-8");String jsonStr = methodReturnStr.substring("json:".length());PrintWriter out = resp.getWriter();out.print(jsonStr);out.flush();}else {super.processTemplate(methodReturnStr, req, resp); //比如 "edit" "index"}}}

此时发现,金额没有获取到,这是因为之前Thymeleaf获取属性是直接通过get方法,而我们的xj专门给它写了get方法,这是数据库查不到的,并且是单独我们封装给查询的时候调用它,进行Bigdecimal乘法算出来的。

现在具体来看我们这个cartItemList到底是怎么查到赋值的,首先它来自于CartItemService的方法getCartItemList,从cartItemDAO层获取同一个user的全部cartItem的List,然后因为是通过反射获取的book字段,没有id值,所以还利用了BookService层的getBook方法把book的属性都查到并赋值给CartItem,然后再通过getCart封装到Map,最后赋值给Cart。这里从DAO查到的CartItem项肯定没有xj的值,是null,因为我们最后是通过Thymeleaf调用实时查出来的。因此我们放入Map前,可以在getCartItemList里面,查到Book值的时候人为调用这个Getxj的方法,然后就会给这个属性赋值,自然最后我们从session域取出来的时候,里面的cartItem都自带xj的值了。

public class CartItemServiceImpl implements CartItemService {private CartItemDAO cartItemDAO = null;private BookService bookService = null;@Overridepublic void addCartItem(CartItem cartItem) {---}@Overridepublic void addOrUpdateCartItem(CartItem cartItem, Cart cart) {---}@Overridepublic List<CartItem> getCartItemList(User user) {List<CartItem> cartItemList = cartItemDAO.getCartItemList(user);for (CartItem cartItem : cartItemList) {Book book = bookService.getBook(cartItem.getBook().getId());cartItem.setBook(book);//此处需要调用getXj(),目的是执行getXj()内部的代码//让book的price乘以buyCount,从而计算出xj这个属性的值cartItem.getXj();}return cartItemList;}@Overridepublic Cart getCart(User user) {List<CartItem> cartItemList = getCartItemList(user);Map<Integer, CartItem> cartItemMap = new HashMap<>();for (CartItem cartItem : cartItemList) {cartItemMap.put(cartItem.getBook().getId(), cartItem);}Cart cart = new Cart();cart.setCartItemMap(cartItemMap);return cart;}
}

这里是xj的方法内部细节 

    public Double getXj() {BigDecimal BigDecimalPrice = new BigDecimal(getBook().getPrice() + "");BigDecimal BigDecimalBuyCount = new BigDecimal(getBuyCount() + "");xj = BigDecimalPrice.multiply(BigDecimalBuyCount).doubleValue();return BigDecimalPrice.multiply(BigDecimalBuyCount).doubleValue();}

此时总金额就能正常显示了 

以前我们的购物车编辑数量是同步的请求,现在我们改成异步的请求

function editCart(cartItemId, buyCount) {window.location.href = 'cart.do?operate=editCart&cartItemId=' + cartItemId + '&buyCount=' + buyCount;
}

此前我们是直接写在外部的js函数,现在我们要写在vue内部,删掉外面同步的这个代码,我们为了达到实时刷新数据的目的,在这个方法被调用的时候后就重新调之前的getCart方法,让它实时再查一次,通过vue更新前端的数据

window.onload = function () {var vue = new Vue({el: "#cart_div",data: {cart:{}},methods: {getCart: function () {axios({method:"POST",url: "cart.do",params: {operate:"cartInfo",}}).then(function (value) {var cart = value.data;vue.cart = cart;}).catch(function (reason) {});},editCart:function (cartItemId, buyCount){axios({method:"POST",url:"cart.do",params: {operate:"editCart",cartItemId: cartItemId,buyCount: buyCount}}).then(function (value) {vue.getCart();}).catch(function (reason) {});}},mounted:function () {this.getCart();}});
}

这里后端我们更新后就不需要让它返回字符串再同步渲染了,我们通过ajax达到了目的,这里企业里可能会通过返回一个代码,然后通过代码能获取到底方法执行的怎么样

public class CartController {private CartItemService cartItemService;public String index(HttpSession session){---}public String cartInfo(HttpSession session){---}public String addCart(Integer bookId, HttpSession session) {---}public String editCart(Integer cartItemId, Integer buyCount) {cartItemService.updateCartItem(new CartItem(cartItemId, buyCount));return "";}
}

此时已经完成了点击按钮异步更新数据的功能,但是总金额和总数这里其实还是Thymeleaf渲染,所以是session下的数据,没有实时更新,同时也是中途调用get才能查到,换成vue需要和刚刚一样中途查询过程赋值

<div>共<span th:text="${session.currUser.cart.getTotalBookCount()}">3</span>件商品</div>
<div class="total-price">总金额<span th:text="${session.currUser.cart.getTotalMoney()}">99.9</span>元</div>

改为 

<div>共<span>{{cart.totalBookCount}}</span>件商品</div>
<div class="total-price">总金额<span>{{cart.totalMoney}}</span>元</div>

老师这里get方法写到了controller层再去通过get方法赋值,但是这里感觉放在更底层的Service层更好,所以我放在了Service层的getCart里面

public class CartItemServiceImpl implements CartItemService {private CartItemDAO cartItemDAO = null;private BookService bookService = null;@Overridepublic void addCartItem(CartItem cartItem) {---}@Overridepublic void updateCartItem(CartItem cartItem) {---}@Overridepublic void addOrUpdateCartItem(CartItem cartItem, Cart cart) {---}@Overridepublic List<CartItem> getCartItemList(User user) {---}@Overridepublic Cart getCart(User user) {List<CartItem> cartItemList = getCartItemList(user);Map<Integer, CartItem> cartItemMap = new HashMap<>();for (CartItem cartItem : cartItemList) {cartItemMap.put(cartItem.getBook().getId(), cartItem);}Cart cart = new Cart();cart.setCartItemMap(cartItemMap);//调用Cart中的三个属性的get方法,目的是在此处计算这三个属性的值,否则这三个属性为null,//导致的结果就是下一步的gson转化时,为null的属性会被忽略cart.getTotalBookCount();cart.getTotalCount();cart.getTotalMoney();return cart;}
}

此时彻底完成向vue的转换,完结撒花。


http://www.ppmy.cn/news/87437.html

相关文章

springboot国际化多语言配置

文章目录 概要springboot项目为例1 新建路径/文件2 新建两个配置类 搞一个控制器测试总结 概要 项目中有时候会用到多语言的业务场景; 一般来说都是通过后端实现的,将先有内容替换为适用的环境语言; springboot项目为例 1 新建路径/文件 新建路径static/i18n新建文件: mess…

Cadence+SPB16.2入门教程(上)

第1章焊盘制作 1.1用Pad Designer制作焊盘 Allegro中制作焊盘的工作叫Pad Designer,所有SMD焊盘、通孔焊盘以及过孔都用该工具来制作。 打开程序->Cadence SPB 16.2->PCB Editer utilities->Pad Designer,弹出焊盘制作的界面,如图1.1所示。 在Units下拉框中选择…

miniconda安装+pycharm安装

miniconda安装pycharm安装 1.miniconda安装2.pycharm安装3.pycharm环境配置 1.miniconda安装 miniconda下载路径&#xff1a;https://docs.conda.io/en/latest/miniconda.html 打开后选择对应的电脑系统及python版本下载 下载完成后双击运行 选择安装路径&#xff0c;记住安装…

Python自动化对每个文件夹及其子文件夹的Excel表加个表头(Excel不同名且有xls文件)...

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 惟将旧物表深情&#xff0c;钿合金钗寄将去。 大家好&#xff0c;我是皮皮。 一、前言 上一篇文章&#xff0c;我们抛出了一个问题&#xff0c;这篇文章…

探索未来:物联网的无限可能

连接万物&#xff0c;创造未来。从智能家居到智慧医疗&#xff0c;从智能车联到智慧城市&#xff0c;物联网技术的影响已经悄然渗透到了我们的方方面面。欢迎大家积极讨论联网技术如何影响了我们的生活。 物联网技术概述 物联网技术&#xff08;Internet of Things&#xff0…

日语文法PPT截图31-45

31 形式名词 とき ところ 作为形式名词的话&#xff0c;一般是要写假名不写汉字的 相对时态 如果是一般时/将来时とき&#xff0c;就是先做后面的动作&#xff0c;在做前面的动作。 出教室的时候&#xff0c;关灯。 如果是过去时とき那么&#xff0c;是先做前面的动作&#…

OJ练习第116题——二进制矩阵中的最短路径(BFS)

二进制矩阵中的最短路径 力扣链接&#xff1a;1091. 二进制矩阵中的最短路径 题目描述 给你一个 n x n 的二进制矩阵 grid 中&#xff0c;返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径&#xff0c;返回 -1 。 二进制矩阵中的 畅通路径 是一条从 左上角 单元格&am…

vector模拟

先来看看vector的源码&#xff0c;string没有看是因为string严格意义上来讲不属于STL。 源代码之间也是存在区别的&#xff0c;大同小异&#xff0c;可以去网上查如何下载STL的源码库。 先看看<vector>文件中的内容&#xff08;当做参考即可&#xff09;&#xff1a; 内容…