Java - Part 14

作者: 低调的灬攻城狮 | 来源:发表于2020-02-26 00:50 被阅读0次

    一、Ajax

    • Ajax可以让浏览器在不刷新页面的情况下。利用js代码和后台进行交互,这种交互方式称之为异步。

    1、原生js的Ajax

    //获取异步对象
    var ajax = new XMLHttpRequest();
    //设置数据, method: 请求模式   url: 地址 arsc: 是否异步
    ajax.open(method,url,async);
    //data: 数据
    ajax.send(data);
    //定义个请求过程中每个状态变化时的回调函数
    ajax.onreadystatechange = function () {
        //当请求进行到第四阶段,也就是有数据返回时,和返回的状态值是200时
        if(ajax.readyState==4&&ajax.status==200){
            //获取返回的数据
            var resp = ajax.responseText;
        }
    }
    
    

    2、jQuery的Ajax

    $.ajax({
        url:"请求地址",
        type:"请求模式",
        data:{"数据名":"数据值"},//js对象
        contentType:"application/json",//默认"application/x-www-form-urlencoded"
        dataType:"json",//默认是 text  , js 会按照预制的数据格式解析数据
        success:function(data){ //请求成功返回之后调用的方法 data:返回的数据    
        }
    })
    

    二、跨域解决方案CORS

    1、同源策略

    • 同源:ip地址+端口号相同
    • 浏览器禁止js访问和当前页面不同源的服务器

    2、跨域

    • 有的时候,我们自己的两个服务器之间需要相互访问,这时就必须要跨域了,比如说图片服务器和本地服务器。要解决跨域问题,就需要浏览器和服务器相互配合,浏览器发出跨域请求,服务器允许跨域请求

    3、两种请求:简单请求与非简单请求

    • 3.1 简单请求
      符合简单请求必须满足以下两个条件:
      • 请求方法是head、get、post这三种方法之一
      • content-type只限于三种类型:application/x-www-form-urlencoded、multipart/form-data、text/plain
      • 不自定义字段
    • 3.2 简单请求基本流程
      • 浏览器如果发现是跨域请求, 就会在请求头中添加Origin字段,该字段的值为当前域名
      • 服务器收到请求后,检查这个字段的值, 判断是否允许这个域名下的请求跨域进来
      • 如果允许的话, 就需要在响应中返回特殊字段, 字段的值要设置为允许请求的域名
      • 当浏览器接受到请求,检查服务返回的特殊字段,如果这个特殊字段中记录的值是符合当前域名, 才会将返回的数据传递给js的接收方法,否则就报错

    响应中的特殊字段:

    • Access-Control-Allow-Origin
      该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
    • Access-Control-Allow-Credentials
      该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
    • Access-Control-Expose-Headers
      该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。
    • withCredentials
      如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段,另一方面,开发者必须在AJAX请求中打开withCredentials属性
      但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials= false
    • 3.3 非简单请求基本流程
      • 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),就请求当前url指向的Servlet中的 OPTIONS方法
      • 如果 OPTIONS 方法返回的信息中没有允许的特殊字段, 浏览器就会拒绝发起正式请求
      • 除了Origin字段,"预检"请求的头信息包括两个特殊字段。
    • Access-Control-Request-Method
      该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT
    • Access-Control-Request-Headers
      该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header
    • 响应字段
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: X-Custom-Header
    Access-Control-Allow-Credentials: true
    Access-Control-Max-Age: 1728000
    
    • Access-Control-Allow-Methods
      ​该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
    • Access-Control-Allow-Headers
      ​如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
    • Access-Control-Allow-Credentials
      ​该字段与简单请求时的含义相同。
    • Access-Control-Max-Age
      ​该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

    4、文件服务器
    将文件但粗存放在一个服务器上有很多好处,此时就需要用到跨域请求,解决跨域请求的最佳方式是在过滤器中对特定源的请求允许跨域

    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebFilter("/*")
    public class CorsFilter implements Filter {
        public void init(FilterConfig filterConfig) throws ServletException { }
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletResponse resp = (HttpServletResponse) servletResponse;
            resp.setHeader("Access-Control-Allow-Origin","http://localhost:8090");//* 表示允许所有
            resp.setHeader("Access-Control-Allow-Methods","post, get");//表示允许post与get请求
            filterChain.doFilter(servletRequest,resp);
        }
        public void destroy() { }
    }
    

    三、用户信息的增删改查

    1、显示用户详情

    在用户详情界面应该展示用户的详细信息,比如用户名、头像、昵称。要完成这些,首先要拿到用户的id,用户的信息在登录的时候就已经存在session中了,可以根据这个来从数据库中查询用户的详细信息,然后放进response中,转发到jsp页面。

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        UserBean userBean = (UserBean) req.getSession().getAttribute("user");
        int id = userBean.getId();
        UserInfo userInfo = userInfoService.getUserInfoByUserId(id);
        req.setAttribute("userInfo",userInfo);
        req.getRequestDispatcher("/WEB-INF/pages/userInfo.jsp").forward(req,resp);
    }
    
    <body style="background: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1578736051725&di=76768c9735298e1e0422b1930727c243&imgtype=0&src=http%3A%2F%2Fimg.pptjia.com%2Fimage%2F20190112%2F43847e4d1e0b3af9623f502c45148e15.jpg)">
        <div class="form">
            <%--个人信息--%>
            <div id="content">
                <form action="/user/editUserInfo">
                    <div class="heading"><h2>个人信息中心</h2></div>
                    <table class="table">
                        <tr>
                            <th>头&ensp;像:</th>
                            <td>
                                <c:if test="${userInfo.icon == null}">
                                    <img id="img" onclick="openFile()" src="http://office-1256119282.file.myqcloud.com/20190730/office-cn/official-web/static/img/ic_logo@2x.png">
                                </c:if>
                                <c:if test="${userInfo.icon != null}">
                                    <img id="img" src="${userInfo.icon}" onclick="openFile()">
                                </c:if>
                                <input type="hidden" name="icon" value="${userInfo.icon}" id="icon">
                                <input type="file" id="file" onchange="upload()" style="display: none">
                            </td>
                        </tr>
                        <tr>
                            <th>昵&ensp;称:</th>
                            <td><input class="inp" name="nickName" value="${user.nickName}"></td>
                        </tr>
                        <tr>
                            <th>真实姓名:</th>
                            <td><input class="inp" name="realName" value="${userInfo.realName}"></td>
                        </tr>
                        <tr>
                            <th>性&ensp;别:</th>
                            <td>
                                <input type="radio" name="sex" value="1"
                                <c:if test="${userInfo.sex==1}"> checked="checked" </c:if> > 男
                                <input type="radio" name="sex" value="2"
                                <c:if test="${userInfo.sex==2}"> checked="checked" </c:if> > 女
                            </td>
                        </tr>
                        <tr>
                            <th>邮&ensp;箱:</th>
                            <td><input class="inp" name="email" value="${userInfo.email}"></td>
                        </tr>
                        <tr>
                            <th>电&ensp;话:</th>
                            <td><input class="inp" name="phone" value="${userInfo.phone}"></td>
                        </tr>
                        <tr>
                            <th>住&ensp;址:</th>
                            <td><input class="inp" name="address" value="${userInfo.address}"></td>
                        </tr>
                        <tr>
                            <td colspan="2">
                                <input type="submit" class="btn" value=修改个人信息>
                                <a href="/shop/toMainPage">返&ensp;回</a>
                            </td>
                        </tr>
                    </table>
                </form>
            </div>
            <hr><hr>
            <div id="addresses">
                <a href="javascript:void(0)" onclick="addAddress()">添&ensp;加</a><br><br>
            </div>
            <%--添加--%>
            <div class="form-group" id="add" style="display: none">
                <table class="table">
                    <tr><td colspan="2"><div class="heading">添加地址</div></td></tr>
                    <tr>
                        <td>收货地址:</td>
                        <td><input class="inp" id="addAddress"></td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            <button class="btn" onclick="addAddressById()">添&ensp;加</button>
                            &ensp;&ensp;&ensp;&ensp;
                            <button class="btn" onclick="cancel()">取&ensp;消</button>
                        </td>
                    </tr>
                </table>
            </div><br>
        </div>
    <br><br>
    </body>
    

    2、修改用户信息

    我们在用户信息详情页面已经展示了用户信息。还提供了修改用户信息的操作,用户点击修改按钮就会触发Ajax操作与数据库后台进行交互,完成用户信息的修改,修改完成之后通过Ajax重新请求当前页面。

    <script>
        //预加载
        $(function () {
            getAddresses();
        });
        //取消添加
        function cancel(){
            $("#content").show(1000);
            $("#add").hide(1000);
        }
        //打开添加框
        function addAddress(){
            $("#content").hide(1000);
            $("#add").show(1000);
        }
        //删除地址
        function deleteAddressById(id) {
            $.ajax({
                url:"/user/deleteAddressById",
                type:"post",
                data:{id:id},
                dataType:"json",
                success:function (data) {
                    if(data.code==-1) {
                        alert(data.message);
                    } else {
                        $("#addresses").empty();
                        getAddresses();
                    }
                }
            });
        }
        //修改地址
        function editAddressById(id) {
            var content = $("#address").val();;
            $.ajax({
                url:"/user/editAddressById",
                type:"post",
                data:{id:id,content:content},
                dataType:"json",
                success:function (data) {
                    if(data.code==-1) {
                        alert(data.message);
                    } else {
                        $("#addresses").empty();
                        getAddresses();
                        location.reload();
                    }
                }
            });
        }
        //添加地址
        function addAddressById() {
            var content = $("#addAddress").val();
            $.ajax({
                url:"/user/addAddressById",
                type:"post",
                data:{content:content},
                dataType:"json",
                success:function (data) {
                    if(data.code==-1) {
                        alert(data.message);
                    } else {
                        $("#addresses").empty();
                        getAddresses();
                        location.reload();
                    }
                }
            });
        }
        //获取用的所有收货地址
        function getAddresses() {
            $.ajax({
                url:"/user/getAddress",
                type:"post",
                dataType:"json",
                success:function (data) {
                    if(data.code == -1) {
                        alert(data.message);
                    } else {
                        var list = data.data;
                        list.forEach(function(item) {
                            var html = "<br><input id='address' class='inp' value='"+item.content+"'> &ensp;&ensp;&ensp;&ensp;" +
                                "<a href='javascript:void(0)' onclick='deleteAddressById("+item.id+")'>删&ensp;除</a>&ensp;" +
                                "<a href='javascript:void(0)' onclick='editAddressById("+item.id+",this)'>修&ensp;改</a>&ensp;<br><br>";
                            $("#addresses").append(html);
                        });
                    }
                }
            });
        }
        //打开文件并上传
        function openFile() {
            $("#file").click();
        }
        function upload() {
            var formData = new FormData();
            formData.append("file",$("#file")[0].files[0]);
            $.ajax({
                url:"http://localhost:8070/FileServer/file/upload",
                type:"post",
                data:formData,
                dataType:"json",
                contentType:false,
                processData: false,
                success:function(data) {
                    if(data.errno == 0) {
                        alert("上传成功");
                        $("#icon").val(data.data[0]);
                        $("#img").attr("src",data.data[0]);
                    } else {
                        alert("上传失败");
                    }
                }
            });
        }
    </script>
    

    四、商品条件筛选与排序

    • 应当提供商品名称的搜索以及商品类型的筛选,但是有一个问题,商品类型这个参数用户可以不选,可以选一个,也可以选多个,处理这种问题需要SQL拼接
    • 用户在购买商品的时候,应该可以进行价格排序与数量排序,既可以正序,也可以倒序,想要解决这个问题就需要在JavaBean中再设置两个字段,这两个字段是字符串用来记录价格排序与数量排序。根据前台发送过来的数据将这两个字符串放进SQL语句中。
    package com.shop.dao;
    
    import com.shop.bean.Goods;
    import com.utils.DBUtils;
    import com.utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ShopDao {
        /**
         * 根据id查找商品详情信息
         * @param goods
         * @return
         */
        public Goods getGoodsById(Goods goods) {
            Connection cn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                cn = JDBCUtils.getConnection();
                ps = cn.prepareStatement("select g.*,t.name as typeName from goods g left join types t on t.id = g.typeId where g.id = ?");
                ps.setInt(1,goods.getId());
                rs = ps.executeQuery();
                Goods goodsBean = DBUtils.selectOne(Goods.class,rs);
                return goodsBean;
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                JDBCUtils.close(rs,ps,cn);
            }
            return null;
        }
        /**
         * 获取全部上架商品
         * @param goods
         * @return
         */
        public List<Goods> getGoods(Goods goods){
            Connection cn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                cn = JDBCUtils.getConnection();
                //拼接预制型sql语句
                //sql语句中每拼接一个问号, 要往数组中存入一个对应的值,
                //总共有几个问号,对应的值的顺序是正确的
                List<Object> objects = new ArrayList<>();
                //sql语句
                String sql = "select * from goods where status=1 ";
                //有商品名称, 拼接
                if(goods.getName()!=null){
                    sql += " and name like ? ";
                    objects.add("%"+goods.getName()+"%");
                }
                //有类型id,拼接
                if(goods.getTypeIds()!=null){
                    sql += " and typeId in (" ;
                    int[] typeIds = goods.getTypeIds();
                    //遍历类型id
                    for (int i = 0; i < typeIds.length; i++) {
                        if(i==typeIds.length-1){
                            sql += "? ) ";
                        }else{
                            sql += "? , ";
                        }
                    }
                    objects.add(goods.getTypeIds());
                }
                //排序
                boolean order = true;
                if (goods.getPriceOrder()!=null&&!goods.getPriceOrder().equals("")){
                    if (order){
                        sql += " order by ";
                        order = false;
                    } else {
                        sql += " , ";
                    }
                    sql += goods.getPriceOrder();
                }
                if (goods.getNumOrder()!=null&&!goods.getNumOrder().equals("")){
                    if (order){
                        sql += " order by ";
                        order = false;
                    } else {
                        sql += " , ";
                    }
                    sql += goods.getNumOrder();
                }
                ps = cn.prepareStatement(sql+" limit ? , ?");
                //设置sql语句对应的参数值
                int n = 0; //记录已经设置了多少个参数值
                for (Object object : objects) {
                    //拿到的值是一个数组, 需要转换并遍历
                    if(object.getClass().isArray()){
                        int[] typeIds = (int[]) object;
                        for (int i = 0; i <typeIds.length; i++) {
                            n++;
                            ps.setObject(n,typeIds[i]);
                        }
                    }else{
                        n++;
                        ps.setObject(n,object);
                    }
                }
                ps.setInt(n+1,goods.getStart());
                ps.setInt(n+2,goods.getPageSize());
                rs = ps.executeQuery();
                List<Goods> list = DBUtils.selectMore(Goods.class,rs);
                return list;
            }catch (Exception  e){
                e.printStackTrace();
            }finally {
                JDBCUtils.close(rs,ps,cn);
            }
            return null;
        }
        /**
         * 获取上架商品数量
         * @param goods
         * @return
         */
        public int getGoodsCount(Goods goods){
            Connection cn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                cn = JDBCUtils.getConnection();
                List<Object> objects = new ArrayList<>();
                String sql = "select count(1) from goods where status=1 ";
                if(goods.getName()!=null){
                    sql += " and name like ?";
                    objects.add("%"+goods.getName()+"%");
                }
                if(goods.getTypeIds()!=null){
                    sql += " and typeId in (" ;
                    int[] typeIds = goods.getTypeIds();
                    for (int i = 0; i < typeIds.length; i++) {
                        if(i==typeIds.length-1){
                            sql += "? )";
                        }else{
                            sql += "? , ";
                        }
                    }
                    objects.add(goods.getTypeIds());
                }
                ps = cn.prepareStatement(sql);
                int n = 0;
                for (Object object : objects) {
                    if(object.getClass().isArray()){
                        int[] typeIds = (int[]) object;
                        for (int i = 0; i <typeIds.length; i++) {
                            n++;
                            ps.setObject(n,typeIds[i]);
                        }
                    }else{
                        n++;
                        ps.setObject(n,object);
                    }
                }
                rs = ps.executeQuery();
                if(rs.next()){
                    return rs.getInt(1);
                }
            }catch (Exception  e){
                e.printStackTrace();
            }finally {
                JDBCUtils.close(rs,ps,cn);
            }
            return 0;
        }
    }
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ include file="/resource/pages/header.jsp"%>
    <html>
    <head>
        <title>商城首页</title>
        <style>
            body { font-family: 楷体; }
            div { text-align: center; }
            .goods{ display: inline-block; }
            img {
                width: 200px;
                height: 200px;
            }
        </style>
        <link rel="stylesheet" href="/resource/css/MyCss.css">
    </head>
    <body style="background: url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1578736051725&di=76768c9735298e1e0422b1930727c243&imgtype=0&src=http%3A%2F%2Fimg.pptjia.com%2Fimage%2F20190112%2F43847e4d1e0b3af9623f502c45148e15.jpg)">
        <div class="form">
            <div class="heading">
                <h3>商城商品页面</h3>
            </div>
            <div class="form-group">
                <form id="form" action="/shop/toMainPage">
                    <input id="search" class="inp" name="name" value="${goods.name}"> <button class="btn">搜索</button>
                    <br>类型 :
                    <c:forEach items="${types}" var="item">
                        ${item.name}
                        <input type="checkbox" name="typeIds" value="${item.id}" onclick="check()"
                        <c:forEach items="${goods.typeIds}" var="typeId">
                               <c:if test="${typeId==item.id}">checked="checked"</c:if>
                        </c:forEach> >
                    </c:forEach><br>
                    <input type="hidden" value="${goods.priceOrder}" name="priceOrder" id="priceOrder">
                    <input type="hidden" value="${goods.numOrder}" name="numOrder" id="numOrder">
                </form>
            </div>
            <div>
                排序:
                <%--价格排序--%>
                <c:if test="${empty goods.priceOrder}">
                    <button class="btn" onclick="priceOrder('price ASC')">价格排序</button>
                </c:if>
                <c:if test="${goods.priceOrder eq 'price ASC'}">
                    <button class="btn" onclick="priceOrder('price DESC')">价格正序</button>
                </c:if>
                <c:if test="${goods.priceOrder eq 'price DESC'}">
                    <button class="btn" onclick="priceOrder('price ASC')">价格倒序</button>
                </c:if>
                <%--数量排序--%>
                <c:if test="${empty goods.numOrder}">
                    <button class="btn" onclick="numOrder('num ASC')">数量排序</button>
                </c:if>
                <c:if test="${goods.numOrder eq 'num ASC'}">
                    <button class="btn" onclick="numOrder('num DESC')">数量正序</button>
                </c:if>
                <c:if test="${goods.numOrder eq 'num DESC'}">
                    <button class="btn" onclick="numOrder('num ASC')">数量倒序</button>
                </c:if>
            </div>
            <div class="form-group">
                <c:forEach items="${list}" var="item">
                    <div class="goods">
                        <img src="${item.icon}">
                        <div>${item.name}</div>
                        <div style="color: lawngreen;font-weight: 600;">${item.price}¥</div>
                        <div style="color: blue">${item.num}件</div>
                        <button class="btn" onclick="toGoodsInfo(${item.id})">加入购物车</button>
                    </div>
                </c:forEach>
            </div><br>
            <div class="paging">
                ${paging}
            </div>
        </div>
    </body>
    <script src="/resource/js/jquery.js"></script>
    <script>
        function check(){
            $("#form").submit();
        }
        function priceOrder(po){
            $("#priceOrder").val(po);
            $("#form").submit();
        }
        function numOrder(po){
            $("#numOrder").val(po);
            $("#form").submit();
        }
        function toGoodsInfo(goodsId){
            location.href = "/shop/toGoodsInfoPage?id="+goodsId;
        }
    </script>
    </html>
    

    相关文章

      网友评论

        本文标题:Java - Part 14

        本文链接:https://www.haomeiwen.com/subject/nsmqxhtx.html