案例3:书城

一.业务分析

1.用户登录,显示欢迎界面

  1. 根据unamepwd获取用户信息
  2. 获取用户的购物车信息
  3. 欢迎界面显示用户的名字,购物车项数量
  4. 显示库存的图书信息

2.购物车操作

  1. 将书籍添加到购物车
    • 创建购物车详情项
    • 添加或者更新购物车信息
  2. 跳转到购物车
    • 重新加载用户的购物车信息
  3. 在购物车中添加或者减少书籍
    • 添加或者更新购物车信息

3.结账

  1. 订单表添加一条记录
    • 创建订单项,设置其属性
    • 添加订单项
  2. 订单详情添加记录
    • 遍历购物车项,添加到订单详情中
  3. 清空购物车记录
    • 遍历购物车项,删除购物车记录
  4. 更新库存信息(未做)

4.查看订单

  1. 获取用户信息
  2. 获取用户对应的订单详情信息

二.数据库设计

2.1t_book:

含义序号书名作者价格销量库存封面状态
名称idbookNameauthorpricesalCountbookCountbookImgbookStatus
类型intvarcharvarcharfloatvarcharintvarchartinyint
约束主键唯一,非空非空默认0

2.2t_user:

含义序号用户名密码邮箱角色
名称idunamepwdemailrole
类型intvarcharvarcharvarchartinyint
约束主键唯一,非空非空

2.3t_cart_item

含义序号书籍数量所属用户
名称idbookBeanbuyCountuserBean
类型intintintint
约束主键外键,非空外键

2.4t_order

含义序号订单编号日期金额数量订单状态所属用户
名称idorderNoorderDateorderMoneyorderCountorderStatususerBean
类型intvarchardatetimedoubleintinttinyint
约束主键唯一,非空非空外键

2.5t_order_detail

含义序号商品数量所属订单
名称idbookBeanbuyCountorderBean
类型intintintint
约束主键外键,非空外键,非空

三.项目细节

1.thymeleaf注意

  1. 头部: <html lang="en" xmlns:th="http://www.thymeleaf.org">

  2. 绝对引用:@{}表示省略到了web/。可以在配置文件中设置前缀和后缀。

  3. 注意"|"的使用:包裹在${}最远的一层,但是要在其他的{}内。

    <img th:src="@{|/static/uploads/${book.bookImg}|}" alt="图片加载失败"}>
    <p th:text="|书名:${book.bookName}|">书名:活着</p>
    

2.跳转页面注意

  1. 页面所有需要的信息重新加载。
  2. 重定向只是刷新页面,其本质是调用了index方法重新加载页面。若需要跳转到非index页面,则不能使用重定向。

3.html点击跳转事件使用

  1. 调用java方法,如登录。需要提交表单

    • 从请求中获取POST请求的参数:request.getParameter(参数名)。这一步由发报机自动完成。
  2. 调用jsp方法,如加购物车。没有提交表单,但是仍然需要提交传参数,且参数为动态参数。

    • 设置点击事件

      th:οnclick="|editCart(${cartItem.id}, ${cartItem.buyCount - 1})|"
      
    • 使用.js函数调用java

      function editCart(cartItemId, buyCount){
          window.location.href="cart.do?operate=editCart&cartItemId=" + cartItemId + "&buyCount=" + buyCount;
      }
      
    • java中实现功能

4.字符集转换

  1. HTML --> JAVA --> MySQL:重点关注HTMLJAVA之间的字符集设置

    • 设置注解:将字符集设置在参数中

      @WebFilter(urlPatterns = {"*.do"}, initParams = {@WebInitParam(name = "encoding", value = "utf-8")})
      
    • 重写init方法:设置默认字符集

      @Override
      public void init(FilterConfig filterConfig) throws ServletException {
          String encodingStr = filterConfig.getInitParameter("encoding");
          if(StringUtil.isNotEmpty(encodingStr)){
              encoding = encodingStr;
          }
      }
      
    • 重写doFIlter方法,修改字符集

      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          //修改默认字符编码
          ((HttpServletRequest)servletRequest).setCharacterEncoding(encoding);
          //放行
          filterChain.doFilter(servletRequest, servletResponse);
      
      }
      
  2. MySQL --> JAVA --> HTML:同上,但无需设置。

  3. 注意:get请求和post请求的字符集设置方式不同

    • 这里之后补充

5.时间转换问题

  1. DAO类型java.util.Date --> 数据库类型datetime。可以直接转换
  2. 数据库类型datetime --> 返回类型 LocalDataTime --> DAO类型java.util.Date报错!!!
    • 解决:把orderDate的类型改成java.time.LocalDataTime

6.使用过滤器限制用户访问的网页

  1. 使用过滤器,但是要注意访问过滤器要放在字符转换过滤器和事务过滤器之后

  2. 过滤器先后顺序规则:

    • 使用注解:按照定义的过滤器名字filterName顺序过滤,从a-z。
    • 使用配置文件:按照web.xml的顺序执行过滤。
  3. 用户限制过滤器

    • 注解:配置过滤内容和过滤白名单

      @WebFilter(urlPatterns = {"*.do", "*.html"},
              initParams = {
                  @WebInitParam(name = "bai", value = "/pro25/page.do?operate=page&page=user/login,/pro25/user.do?null")
              })
      
    • 重写init方法:获取注解中的白名单列表

      @Override
      public void init(FilterConfig config) throws ServletException {
          String bai = config.getInitParameter("bai");
          String[] baiArr = bai.split(",");
          baiList = Arrays.asList(baiArr);
      }
      
    • 重写doFilter方法

      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          //将请求和响应强制类型转换
          HttpServletRequest request = (HttpServletRequest)servletRequest;
          HttpServletResponse response = (HttpServletResponse)servletResponse;
      
          //http://localhost:8080/pro25/page.do?operate=page&page=user/login
          //System.out.println("request.getRequestURI() = " + request.getRequestURI());
          //System.out.println("request.getQueryString() = " + request.getQueryString());
      
          //拼接请求字符串
          String requestURI = request.getRequestURI();
          String queryString = request.getQueryString();
          String str = requestURI + "?" + queryString;
      
          if(baiList.contains(str)){//如果请求白名单内容,放行
              filterChain.doFilter(request, response);
          }else {
              HttpSession session = request.getSession();
              Object curUserObj = session.getAttribute("curUser");
              if (curUserObj == null) {//如果用户没有登录,跳转到登录界面
                  response.sendRedirect("page.do?operate=page&page=user/login");
              } else {//若用户已经登录,放行
                  filterChain.doFilter(request, response);
              }
          }
      }
      

7. 通过反射获取方法的参数列表名称

正常情况Java编译时,默认反射参数列表的名称为arg0,arg1...。想要返回参数列表的字符串名称:参考CSDN

建议修改pom文件:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

四.一些其他技术

1.Cookie

  1. 设置Cookie

    //1.创建cookie对象
    Cookie cookie = new Cookie("uname", "Lifeifan");
    //2.将cookie保存到客户端
    resp.addCookie(cookie);
    //3.跳转页面
    req.getRequestDispatcher("hello01.html").forward(req,resp);
    
  2. 设置Cookie的有效时长:一般采用默认

    cookie.setMaxAge(60)		//设置cookie的有效时长60s
    cookie.setDomin(pattern);	//设置
    cookie.setPath(uri);		//设置传递cookie的路径,默认为全部
    
  3. Cookie的应用

    • 记住用户名和密码10天
    • 10天免登录

2.Kaptcha:验证码

  1. 添加jar包

  2. web.xml文件中注册KaptchaServlet,并设置图片的相关属性

    • 注册:验证码图片的src="kaptch.jpg",对应到KaptchaServleturl-pattern中。

      <servlet>
          <servlet-name>KaptchaServlet</servlet-name>
          <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
      </servlet>
      
      <servlet-mapping>
          <servlet-name>KaptchaServlet</servlet-name>
          <url-pattern>/kaptch.jpg</url-pattern>
      </servlet-mapping>
      
      <img src="kaptch.jpg" alt="图片加载失败">
      
    • 验证码属性:com.google.code.kaptcha.Constants。例如:

      <init-param>
          <param-name>kaptcha.border.color</param-name>
          <param-value>red</param-value>
      </init-param>
      
  3. 校验。Kaptcha在生成验证码图片时,会将验证码信息保存到session中。

  4. 异常:

    • 没有加载图片:1.检查注册是否正确。2.重启Toncat

3.正则表达式

  1. 定义:在JavaScript中定义

    • 对象形式:var reg = new RegExp("abc","g");
    • 直接量形式:var reg = /abc/g
  2. 匹配模式

    • g 全局匹配
    • i 忽略大小写
    • m 多行匹配
  3. 注册时校验用户信息

    • <form th:action="@{/user.do}" method="post" onsubmit="return preRegist()">中的onsubmit

      • "return true"点击时提交表单
      • "return false"点击时不提交表单
    • 使用JavaScript验证表单信息

      • 获取表单参数

        //方式一,DOM: Document
        var unameText = document.getElementById("unameText");
        //方式二,BOM: Browser
        var unameText = document.forms[0].uname;
        
      • 校验表单

        //验证邮箱
        var email = $("emailText").value;
        var emailSpan = $("emailSpan");
        var emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
        if(!emailReg.test(email)){
            emailSpan.style.visibility="visible";
            return false
        }else{
            emailSpan.style.visibility="hidden";
        }
        

4.异步请求Ajax

目的:可以开辟一个新的线程,用来发送异步请求,然后当服务器给我们响应的时候进行回调操作

优势:提高用户体验,避免请求白页面;使得网页局部刷新:降低服务器负担,浏览器压力,网络带宽压力

案例:当用户名失去焦点时,验证当前用户名是否已经被注册。

  1. HTML页面端,设置失去焦点事件

    <input id="unameText" type="text" name="uname" placeholder="请输入用户名" value="lff" onblur="ckUname(this.value)"/>
    
  2. js文件中定义ckUname(uname)方法

    //1.如果想要发送异步请求,需要一个对象"XMLHttpRequest"
    var xmlHttpRequest ;
    
    //2.因为不同的浏览器的创建规则不同,所以使用一个方法来创建
    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("Msxm12.XMLHTTP");
            }
    
        }
    }
    
    //3.在ckUname方法中创建xmlHttpRequest对象,并发送请求
    function ckUname(uname){
        createXMLHttpRequest();
        var url = "user.do?operate=ckUname&uname=" + uname;
        //3.1调用open方法
        xmlHttpRequest.open("GET",url,true);
        //3.2设置回调函数
        xmlHttpRequest.onreadystatechange = ckUnameCB;
        //3.3发送请求
        xmlHttpRequest.send();
    }
    
    //4.回调函数
    function ckUnameCB(){
        //判断xmlHttpRequest的状态
        //xmlHttpRequest.readyState的响应码:
        //0 - (未初始化)还没有调用send()方法
        //1 - (载入)已调用send()方法,正在发送请求
        //2 - (载入完成)send()方法已执行,已经接收到全部响应内容
        //3 - (交互)正在解析响应内容
        //4 - (完成)响应内容解析完成,客户端可以调用
        if(xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
            //xmlHttpRequest.responseText表示服务器端响应的文本
            alert(xmlHttpRequest.responseText);
        }
    }
    
  3. 修改中央控制器:

    //3.3请求调用的函数
    public String ckUname(String uname){
        User user = userService.getUser(uname);
        if(user != null){
            //用户名被占用
            return "json:{'uname':'1'}";
        }else{
            //可以注册
            return "json:{'uname':'0'}";
        }
    }
    
    //中央控制器处理返回字符串
    if(methodReturnStr.startsWith("json:")){
        String jsonStr = methodReturnStr.substring("json:".length());
        PrintWriter writer = resp.getWriter();
        writer.print(jsonStr);
        writer.flush();
    }
    

5.VUE

  1. 背景知识:

    • 创建js对象

      //方式一
      var persion = new Object();
      persion.pid = "p001";
      persion.pname = "jim";
      persion.sayHello = function(){
          alert("Hello, " + persion.pid);	
      }
      //方式二
      var persion = {
          "pid":"p001",
          "pname":"李非凡",
          "sayHello":function (){
              alert("Hello, " + persion.pname);
          }
      }
      
  2. 简单使用

    • 绑定文本信息,属性,和双向绑定

      <!--在JavaScript中创建Vue对象,并通过标签id进行绑定-->
      <script language="JavaScript">
          window.onload=function(){
              var vue = new Vue({
                  "el":"#div0",
                  data:{
                      msg:"hello world!",
                      uname:"里非凡"
                  }
              });
          }
      </script>
      <!--在html中进行绑定-->
      <div id="div0">
          <!--在对应的标签中使用msg文本-->
          <span>{{msg}}</span>
          <!--属性:在对应的标签中, 通过"v-bind:"使用属性。注意"v-bind"可以省略,保留":"-->
          <input type="button" v-bind:value="uname" onclick="hello()">
          <!--双向绑定:"v-model:value"中的":value"可以省略-->
          <input type="text"  v-model:value="msg" >
      </div>
      
    • 条件标签v-ifv-else。补充v-show:通过display控制标签的显示。

      <div v-if="num%2==0" style="width: 200px; height: 200px; background-color: orange;"></div>
      <div v-else="num%2==0" style="width: 200px; height: 200px; background-color: aqua;"></div>
      
    • 迭代标签v-for

      <tr v-for="fruit in fruitList" align="center">
          <td>{{fruit.fname}}</td>
          <td>{{fruit.price}}</td>
          <td>{{fruit.fcount}}</td>
          <td>{{fruit.remark}}</td>
      </tr>
      
    • 绑定点击事件v-on:click,可以简写为@click

      methods:{
          reverseStr:function(){
              this.msg = this.msg.split("").reverse().join("");
          }
      }
      
      <div id="div0">
          <span>{{msg}}</span><br/>
          <input type="button" value="反转" v-on:click="reverseStr">
      </div>
      
    • 监听属性值改动

      watch:{
          num1:function(newValue){
              this.num3 = newValue + this.num2;
          },
          num2:function(newValue){
              this.num3 = newValue + this.num1;
          }
      }
      
      <input type="text" v-model="num1">
      <input type="text" v-model="num2">
      <span>{{num3}}</span><br/>
      
    • 生命周期

      <script language="JavaScript">
          window.onload=function(){
          var vue = new Vue({
              "el":"#div0",
              data:{
                  msg:"这里是msg。。。"
              },
              methods:{
                  changeMsg:function(){
                      if(this.msg == "这里是msg。。。"){
                          this.msg = "msg被改变";
                      }else{
                          this.msg = "这里是msg。。。";
                      }
                  }
              },
              //生命周期
              beforeCreate:function(){
                  console.log("beforeCreate:vue对象创建之前--------");
                  console.log("msg:" + this.msg);
              },
              created:function(){
                  console.log("created:vue对象创建之后--------");
                  console.log("msg:" + this.msg);
              },
              beforeMount:function(){
                  console.log("beforeMount:数据装载之前--------");
                  console.log("msg:" + document.getElementById("span").innerText);
              },
              mounted:function(){
                  console.log("mounted:数据装载之后--------");
                  console.log("msg:" + document.getElementById("span").innerText);
              },
              beforeUpdate:function(){
                  console.log("beforeUpdate:数据更新之前--------");
                  console.log("msg:" + document.getElementById("span").innerText);
              },
              updated:function(){
                  console.log("updated:数据更新之后--------");
                  console.log("msg:" + document.getElementById("span").innerText);
              },
          });
      }
      </script>
      
      <div id="div0">
          <span id="span">{{msg}}</span><br/>
          <input type="button" value="改变msg的值" @click="changeMsg">
      </div>
      
  3. 错误原因

    • 创建对象时检查VueV是否大写

6.Axios:是Ajax的一个框架

  1. 导入axiosjs文件:<script language="JavaScript" src="script/axios.min.js"></script>

  2. 调用方法

    <input type="button" value="点击发送异步请求" @click="lff">
    
  3. vue的方法中配置axios,向服务器发送普通数据格式

    lff:function(){
        axios({
            method:"POST",
            url:"axiso02.do",
            params:{
                uname:vue.uname,
                pwd:vue.pwd
            }
        })
            .then(function (value) {
            console.log(value);
        })
            .catch(function (reason) {
            console.log(reason);
        })
    }
    

7.JSON数据格式,特点:简洁,节约网络带宽

7.1客户端向服务器发送JSON数据格式

+++客户端发送JSON数据格式

  1. params改成data

  2. 发送格式

    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);
        });
    }
    
  3. 问题:无法发送JSON格式的数据,可以发送普通格式

    • 原因:axios的键值method写成了mathod

+++服务器接受JSON格式

  1. 使用流JSON为字符串

    //1.创建接收流
    BufferedReader reader = req.getReader();
    //2.创建缓冲字符串
    String str = null;
    //3.创建拼接字符串
    StringBuffer stringBuffer = new StringBuffer("");
    //4.接收并拼接字符串
    while((str = reader.readLine()) != null){
        stringBuffer.append(str);
    }
    //5.关闭流资源
    reader.close();
    //6.还原JSON
    str = stringBuffer.toString();
    System.out.println("str = " + str);
    
  2. JSON字符串转化为类

    //1.获取GSON类
    Gson gson = new Gson();
    //2.使用GSON类将字符串转化为对应类
    User user = gson.fromJson(str, User.class);
    

7.2服务器向客户端发送JSON数据格式

+++服务器发送JSON格式

  1. 将类转换为JSON格式

    //1.将类转换为`JSON`格式
    String userJsonStr = gson.toJson(user);
    //2.设置响应的编码格式
    resp.setCharacterEncoding("UTF-8");
    //3.设置MIME-TYPE
    resp.setContentType("application/json;charset=UTF-8");
    //4.执行响应
    resp.getWriter().write(userJsonStr);
    

    注意:第三步可以参考链接

+++客户端接收JSON数据并转化为js

  1. 接收并手动转化为js

    var data = value.data;
    console.log(data);
    vue.uname=data.uname;
    vue.pwd=data.pwd;
    
  2. 若需要json对象,将字符串转化为JSON对象JSON.parse()

    var str = "{\"uname\":\"lfff\",\"age\":20}";
    //使用JSON.parse()转换
    var user = JSON.parse(str);
    alert(user.uname + "_" + user.age);
    

    格式化:看得懂–>看不懂(统一格式)

    解析:看不懂–>看得懂(直观)

    补充:将js对象转化为字符串JSON.stringify()

    var user = {"uname":"王林林","age":18};//js对象
    var str = JSON.stringify(user);
    
  3. 报错:

    • 无法转换成json对象,原因:“:”写成了“=”

8.实战应用:使用vue+axios替换thymeleaf

  1. 导入vueaxiosjs文件,并添加引用

  2. 将原网页的动态文本替换为vue文本,属性替换为vue属性

  3. 源文件的局部动态数据加载和更新,使用vue对象的方法调用axios异步请求

    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){
                        	//接收返回的数据,并更新vue的属性
                            console.log(value.data);
                            var cart = value.data;
                            vue.cart = cart;
                        })
                        .catch(function (reason){
                            console.log(reason.data);
                        })
                },
                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){
                            console.log(reason.data);
                        })
                }
            },
            mounted:function(){
                this.getCart();
            }
        });
    };
    

    })
    },
    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){
    console.log(reason.data);
    })
    }
    },
    mounted:function(){
    this.getCart();
    }
    });
    };

    
    
    
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值