项目实战系列三: 家居购项目 第六部分

news2024/11/25 1:04:38

文章目录

      • 🌈Ajax检验注册名
      • 🌈Ajax添加购物车
      • 🌈上传与更新家居图片
      • 🌈作业布置
        • 🍍会员登陆后不能访问后台管理
        • 🍍解决图片冗余问题
        • 🍍分页导航完善

🌈Ajax检验注册名

需求分析

  1. 注册会员时, 如果名字已经注册过, 当光标离开输入框, 提示会员名已经存在, 否则提示不存在
  2. 要求使用ajax完成

程序框架图
在这里插入图片描述

  1. MemberServlet - 返回json格式的字符串 - 方式一
protected void isExistByName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //1.获取用户名
   String username = req.getParameter("username");
   //2.调用service
   boolean existsByUsername = memberService.isExistsByUsername(username);

   //3.思路
   //(1)如果返回json格式[不要乱写, 要根据前端的需求来写]
   //(2)因为前后端都是我们自己写的, 格式我们自己定义
   //(3){"isExist": true};
   //(4)先用最简单的方法拼接 => 一会改进[扩展]
   String resultJson = "{\"isExist\": " + existsByUsername + "}";

   //4.返回
   resp.getWriter().print(resultJson);
}

返回json格式的字符串 - 方式二

protected void isExistByName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //1.获取用户名
   String username = req.getParameter("username");
   //2.调用service
   boolean existsByUsername = memberService.isExistsByUsername(username);

   //3.思路
   //(1)如果返回json格式[不要乱写, 要根据前端的需求来写]
   //(2)因为前后端都是我们自己写的, 格式我们自己定义
   //(3){"isExist": true};
   //(4)先用最简单的方法拼接 => 一会改进[扩展]
   //String resultJson = "{\"isExist\": " + existsByUsername + "}";字符串就不需要再转
   //(5)将要返回的数据封装成map => json格式
   Map<Object, Object> map = new HashMap<>();
   map.put("isExist", existsByUsername);
   //map.put("email", "978964140@qq.com");
   //map.put("phone", "13031748275");

   //4.返回json格式的数据
   Gson gson = new Gson();
   String resultJson = gson.toJson(map);
   resp.getWriter().print(resultJson);
}
  1. 前端
$("#username").mouseleave(function () {//鼠标离开事件[无需点击, 即可触发]
     var usernameValue = $(this).val();
     $.getJSON(
         //这里尽量准确, 一把确定[复制粘贴]
         "memberServlet", "action=isExistByName&username=" + usernameValue, function (data) {
             alert(data.isExist);
             console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()
         }
/*========================================================================================*/
         "memberServlet?action=isExistByName&username=" + usernameValue, function (data) {
             alert(data.isExist);
             console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()
         }
/*========================================================================================*/
         "memberServlet",
         {
             action: "isExistByName",
             username: usernameValue
         },
         function (data) {
             alert(data.isExist);
             console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()
         }
/*========================================================================================*/
         "memberServlet",
         {
             "action": "isExistByName",
             "username": usernameValue
         },
         function (data) {
             alert(data.isExist);
             //前端人员只能通过console.log()来查看你的数据, 然后才知道怎么获取你的数据
             console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()
             if (data.isExist) {
                  $("span[class='errorMsg']").text("用户名 " + usernameValue + " 不可用");
             } else {
                  $("span[class='errorMsg']").text("用户名 " + usernameValue + " 可用");
             }
     )
}      
  • Ajax检验验证码
  1. MemberServlet
   protected void verifyCaptcha(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //获取用户提交的验证码
       String captcha = req.getParameter("captcha");
       //从session中获取 生成的验证码
       HttpSession session = req.getSession();
       String token = (String) session.getAttribute(KAPTCHA_SESSION_KEY);
       //立即删除session中的验证码, 防止该验证码被重复使用
       session.removeAttribute(KAPTCHA_SESSION_KEY);

       //如果token不为空, 并且和用户提交的验证码保持一致, 就继续
       if (token != null) {
           Map<Object, Object> map = new HashMap<>();
           boolean verifyCaptcha = token.equalsIgnoreCase(captcha);
           map.put("verifyCaptcha", verifyCaptcha);

           //返回json格式的数据
           Gson gson = new Gson();
           String resultJson = gson.toJson(map);
           resp.getWriter().print(resultJson);
       }
   }
  1. 前端
    $("#code").blur(function () {//光标焦点离开事件[点击后离开, 才可以触发]
        var captchaValue = this.value;
        $.getJSON(
            "memberServlet?action=verifyCaptcha&captcha="+captchaValue, function (data) {
                console.log("data= ", data);
                if (data.verifyCaptcha) {
                    $("span.errorMsg2").text("验证码正确");
                } else {
                    $("span.errorMsg2").text("验证码错误");
                }
            }
        );
    })

在验证码标签旁补充一个span标签

<span class="errorMsg2"  style="float: right; font-weight: bold; font-size: 15pt; 
               margin-left: 10px; color: lightgray;"></span>                                            

🌈Ajax添加购物车

  1. CartServlet添加addItemByAjax方法
//添加一个添加家居到购物车的方法 [Ajax]
    protected void addItemByAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int id = DataUtils.parseInt(request.getParameter("id"), 1);//家居id
        //根据id获取对应的家居信息
        Furn furn = furnService.queryFurnById(id);
        //先把正常的逻辑走完, 再处理异常的情况
        //如果某家居的库存为0, 就不要添加到购物车, 直接请求转发到首页面
        //if (furn.getInventory() <= 0) {
        //    request.getRequestDispatcher("/index.jsp").forward(request, response);
        //    return;
        //}

        HttpSession session = request.getSession();
        Cart cart = (Cart) session.getAttribute("cart");
        //得到购物车 有可能是空的,也有可能是上次的
        if (cart == null) {
            cart = new Cart();
            session.setAttribute("cart", cart);
        }
        //构建一条家居明细: id,家居名,数量, 单价, 总价
        //count类型为Integer, 不赋值默认值为null
        CartItem cartItem = new CartItem(id, furn.getName(), 1, furn.getPrice(), furn.getPrice());
        //将家居明细加入到购物车中. 如果家居id相同,数量+1;如果是一条新的商品,那么就新增
        cart.addItem(cartItem, furn.getInventory());
        System.out.println("cart= " + cart);

        //规定格式 {"cartTotalCount": 3}

        //方式一:
        //String resultJson = "{\"cartTotalCount\": " + cart.getTotalCount() + "}";
        //response.getWriter().print(resultJson);

        //方式二: 创建map,可扩展性强
        Map<Object, Object> map = new HashMap<>();
        map.put("cartTotalCount", cart.getTotalCount());
        //转成json
        Gson gson = new Gson();
        String resultJson = gson.toJson(map);
        //返回
        response.getWriter().print(resultJson);

        //String referer = request.getHeader("referer");
        //response.sendRedirect(referer);
    }
  1. 前端
            //给所有选定的button都赋上点击事件
            $("button.add-to-cart").click(function () {
                var id = $(this).attr("furnId");
                //location.href = "cartServlet?action=addItem&id=" + id;

                //这里我们使用jquery发出ajax请求, 得到数据进行局部刷新, 解决刷新这个页面效率低的问题
                $.getJSON(
                    "cartServlet?action=addItemByAjax&id=" + id, function (data) {
                        console.log("data=", data);
                        //刷新局部 <span class="header-action-num"></span>
                        $("span.header-action-num").text(data.cartTotalCount);
                    }
                )
            });
  1. 解决Ajax请求转发失败
    测试, 会发现针对ajax的重定向和请求转发会失败, 也就是AuthFilter.java的权限拦截不生效, 也就是点击Add to Cart, 后台服务没有响应

使用ajax向后台发送请求跳转页面无效的原因

  1. 主要是服务器得到的是ajax发送过来的request, 也就是说这个请求不是浏览器请求的, 而是ajax请求的. 所以servlet根据request进行请求转发或重定向都不能影响浏览器的跳转
  2. 解决方案: 如果想要实现跳转, 可以返回url给ajax, 在浏览器执行window.location(url);
    在这里插入图片描述

工具类添加方法 - 判断请求是不是一个ajax请求

   /**
    * 判断请求是不是一个ajax请求
    * @param request
    * @return
    */
   public static boolean isAjaxRequest(HttpServletRequest request) {
       //X-Requested-With: XMLHttpRequest
       return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
   }

修改AuthFilter.java

if (member == null) {//说明用户没有登录
   if (!WebUtils.isAjaxRequest(request)) {//如果不是ajax请求
       //转发到登陆页面, 转发不走过滤器
       servletRequest.getRequestDispatcher("/views/member/login.jsp")
               .forward(servletRequest, servletResponse);
   } else {//如果是ajax请求
       //返回ajax请求, 按照json格式返回 {"url": url}    
       //String url = "views/member/login.jsp";
       //String resultJson = "{\"url\": \"" + url + "\"}";
       
       //1.构建map
       Map<Object, Object> map = new HashMap<>();
       map.put("url", "views/member/login.jsp");
       //2.转成json字符串
       String resultJson = new Gson().toJson(map);
       //3.返回
       servletResponse.getWriter().print(resultJson);
   }

   重定向-拦截-重定向-拦截-重定向-拦截
   //((HttpServletResponse) servletResponse)
   //        .0sendRedirect(request.getContextPath() + "/views/member/login.jsp");
   return;//直接返回
}

修改getJson

//这里我们使用jquery发出ajax请求, 得到数据进行局部刷新, 解决刷新这个页面效率低的问题
$.getJSON(
   "cartServlet?action=addItemByAjax&id=" + id, function (data) {
       console.log("data=", data);
       if (data.url == undefined) {
           //刷新局部 <span class="header-action-num"></span>
           $("span.header-action-num").text(data.cartTotalCount);
       } else {
           location.href = data.url;
       }
   }
)

🌈上传与更新家居图片

引入文件上传下载的包: commons-io-1.4.jar, commons-fileupload-1.2.1.jar
FurnDAOImpl的查询语句加上图片字段 image_path as imagePath

需求分析

  1. 后台修改家居, 可以点击图片, 选择新的图片
  2. 这里会用到文件上传功能

思路分析-程序框架图
在这里插入图片描述

  1. furn_update.jsp
   <style type="text/css">

       #pic {
           position: relative;
       }

       input[type="file"] {
           position: absolute;
           left: 0;
           top: 0;
           height: 180px;
           opacity: 0;
           cursor: pointer;
       }
   </style>
<script type="text/javascript">
   function prev(event) {
       //获取展示图片的区域
       var img = document.getElementById("preView");
       //获取文件对象
       var file = event.files[0];
       //获取文件阅读器: Js的一个类, 直接使用即可
       var reader = new FileReader();
       reader.readAsDataURL(file);
       reader.onload = function () {
           //给img的src设置图片url
           img.setAttribute("src", this.result)
       }
   }
</script>

去掉a标签

<div id="pic">
   <img class="img-responsive ml-3" src="${requestScope.furn.imagePath}"
        alt="" id="preView">
   <input type="file" name="imagePath" id="" value="${requestScope.furn.imagePath}"
          onchange="prev(this)"/>
</div>
  1. 分析空指针异常
    将form表单改成文件表单
    <form action="manage/furnServlet" method="post" enctype="multipart/form-data"></form>
    点击修改家居
    在这里插入图片描述
    报错
    在这里插入图片描述
    将web.xml中500的错误提示配置注销掉, 将异常信息暴露出来
    在这里插入图片描述
    再次点击修改家居信息, 报错信息显示出来, BasicServlet空指针异常
    所以有时候报错信息显示出来很重要
    在这里插入图片描述
    分析: 如果表单是enctype=“multipart/form-data”, 那么req.getParameter(“action”) 的方法得不到action值, 所以BasicServlet会报错
    在这里插入图片描述
    具体原因: req.getParameter(“action”)取不到form-data里的数据
    在这里插入图片描述
  2. 解决空指针异常
    解决方案: 将参数action, id, pageNo以url拼接的方式传参, BasicServlet便不会出错
    注意: post请求可以人为主动在地址中拼接参数,拼接的参数可以直接像get那样接收
    <form action="manage/furnServlet?action=update&id=${requestScope.furn.id}&pageNo=${param.pageNo}" method="post" enctype="multipart/form-data">
    在这里插入图片描述
  3. FurnServlet update方法
    处理普通字段
if (fileItem.isFormField()) {//文本表单字段
   将提交的家居信息, 封装成Furn对象
   switch (fileItem.getFieldName()) {
       case "name":
           furn.setName(fileItem.getString("utf-8"));
           break;
       case "business":
           furn.setBusiness(fileItem.getString("utf-8"));
           break;
       case "price":
           furn.setPrice(new BigDecimal(fileItem.getString()));
           break;
       case "saleNum":
           furn.setSaleNum(Integer.parseInt(fileItem.getString()));
           break;
       case "inventory":
           furn.setInventory(Integer.parseInt(fileItem.getString()));
           break;
   }
}

处理文件字段
在这里插入图片描述
将文件上传路径保存成一个常量

public class WebUtils {
   public static final String FURN_IMG_DIRECTORY = "assets/images/product-image/";
}    
//文件表单字段 => 获取上传的文件的名字
String name = fileItem.getName();

//如果用户没有选择新的图片, name = ""
if (!"".equals(name)) {
   //1.把上传到到服务器 temp目录下的文件保存到指定的目录
   String filePath = "/" + WebUtils.FURN_IMG_DIRECTORY;
   //2.获取完整的目录
   String fileRealPath = req.getServletContext().getRealPath(filePath);
   System.out.println("fileRealPath= " + fileRealPath);
   //3.创建这个上传的目录
   File fileRealPathDirectory = new File(fileRealPath);
   if (!fileRealPathDirectory.exists()) {
       fileRealPathDirectory.mkdirs();
   }
   //4.将文件拷贝到fileRealPathDirectory目录下
   //对上传的文件名进行处理, 前面增加一个前缀, 保证是唯一的即可. 防止文件名重复造成覆盖
   //构建了一个上传的文件的完整路径[目录+文件名]
   name = UUID.randomUUID().toString() + "_" + System.currentTimeMillis() + "_" + name;
   String fileFullPath = fileRealPathDirectory + "\\" + name;
   //保存
   fileItem.write(new File(fileFullPath));
   //关闭流
   fileItem.getOutputStream().close();
   //更新家居图的图片
   furn.setImagePath(WebUtils.FURN_IMG_DIRECTORY + name);
}

全部代码

protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //将提交修改的家居信息,封装成Furn对象

   //如果你的表单是enctype="multipart/form-data", req.getParameter("id") 得不到id
   int id = DataUtils.parseInt(req.getParameter("id"), 0);
   //获取到对应furn对象[从db中获取]
   Furn furn = furnService.queryFurnById(id);
   //todo 如果furn为null, 则return

   //1.判断是不是文件表单
   if (ServletFileUpload.isMultipartContent(req)) {
       //2.创建DiskFileItemFactory对象, 用于构建一个解析上传数据的工具对象
       DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
       //3.构建一个解析上传数据的工具对象
       ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
       //解决中文乱码问题
       servletFileUpload.setHeaderEncoding("utf-8");
       //4.servletFileUpload对象可以把表单提交的数据[文本/文件], 封装到FileItem文件项中
       try {
           List<FileItem> list = servletFileUpload.parseRequest(req);
           for (FileItem fileItem : list) {
               //判断是不是一个文件 => 文本表单字段
               if (fileItem.isFormField()) {
                   将提交的家居信息, 封装成Furn对象
                   switch (fileItem.getFieldName()) {
                       case "name"://家居名
                           furn.setName(fileItem.getString("utf-8"));
                           break;
                       case "business"://制造商
                           furn.setBusiness(fileItem.getString("utf-8"));
                           break;
                       case "price"://价格
                           furn.setPrice(new BigDecimal(fileItem.getString()));
                           break;
                       case "saleNum"://销量
                           furn.setSaleNum(Integer.parseInt(fileItem.getString()));
                           break;
                       case "inventory"://库存
                           furn.setInventory(Integer.parseInt(fileItem.getString()));
                           break;
                   }
               } else {
                   //文件表单字段 => 获取上传的文件的名字
                   String name = fileItem.getName();

                   //如果用户没有选择新的图片, name = ""
                   if (!"".equals(name)) {
                       //1.把上传到到服务器 temp目录下的文件保存到指定的目录
                       String filePath = "/" + WebUtils.FURN_IMG_DIRECTORY;
                       //2.获取完整的目录
                       String fileRealPath = req.getServletContext().getRealPath(filePath);
                       System.out.println("fileRealPath= " + fileRealPath);
                       //3.创建这个上传的目录
                       File fileRealPathDirectory = new File(fileRealPath);
                       if (!fileRealPathDirectory.exists()) {
                           fileRealPathDirectory.mkdirs();
                       }
                       //4.将文件拷贝到fileRealPathDirectory目录下
                       //对上传的文件名进行处理, 前面增加一个前缀, 保证是唯一的即可. 防止文件名重复造成覆盖
                       //构建了一个上传的文件的完整路径[目录+文件名]
                       name = UUID.randomUUID().toString() + "_" + System.currentTimeMillis() + "_" + name;
                       String fileFullPath = fileRealPathDirectory + "\\" + name;
                       //保存
                       fileItem.write(new File(fileFullPath));
                       //关闭流
                       fileItem.getOutputStream().close();
                       //更新家居图的图片
                       furn.setImagePath(WebUtils.FURN_IMG_DIRECTORY + name);
                   }
               } 
           } else {
               System.out.println("不是文件表单...");
           }

           //更新furn对象->DB
           furnService.updateFurn(furn);
           System.out.println("更新成功...");
           //请求转发到 update_ok.jsp
           req.getRequestDispatcher("/views/manage/update_ok.jsp")
                   .forward(req, resp);
       } catch (Exception e) {
           throw new RuntimeException(e);
       }
   }
}

将checkout.jsp复制成update_ok.jsp

<a class="active" href="manage/furnServlet?action=page&pageNo=${param.pageNo}">
   <h4>家居修改成功, 点击返回家居管理页面</h4>
</a>

🌈作业布置

🍍会员登陆后不能访问后台管理

需求分析

  1. 管理员admin登陆后, 可访问所有页面
  2. 会员登陆后, 不能访问后台管理相关页面, 其他页面可以访问
  3. 假定管理员名字就是admin, 其它会员名就是普通会员

AuthFilter - 代码

   @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("请求/cartServlet 被拦截...");
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        //得到请求的url
        String url = request.getServletPath();
        System.out.println("url= " + url);

        //判断是否要验证
        if (!excludedUrls.contains(url)) {
            //获取到登陆的member对象
            Member member = (Member) request.getSession().getAttribute("member");

            if (member == null) {//说明用户没有登录
                if (!WebUtils.isAjaxRequest(request)) {//如果不是ajax请求
                    //转发到登陆页面, 转发不走过滤器
                    servletRequest.getRequestDispatcher("/views/member/login.jsp")
                            .forward(servletRequest, servletResponse);
                } else {//如果是ajax请求
                    //返回ajax请求, 按照json格式返回 {"url": url}
                    //1.构建map
                    Map<Object, Object> map = new HashMap<>();
                    map.put("url", "views/member/login.jsp");
                    //2.转成json字符串
                    String resultJson = new Gson().toJson(map);
                    //3.返回
                    servletResponse.getWriter().print(resultJson);
                }

                return;//直接返回
            }
            //如果member不为空
            if ("admin".equals(member.getUsername())) {//管理员登陆
                //全部放行

            } else {//普通用户登录, 部分页面不能放行
                //如果该用户不是admin, 但是它访问了后台, 就转到管理员登录页面
                //if ("/manage/furnServlet".equals(url) || url.contains("/views/manage/")) {
                
                //.* 匹配任意个字符
                if ("/manage/furnServlet".equals(url) || url.matches("^/views/manage/.*")) {
                    request.getRequestDispatcher("/views/manage/manage_login.jsp")
                            .forward(servletRequest, servletResponse);
                }
            }
        }

        //如果请求的是登录页面, 那么就放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("请求/cartServlet验证通过, 放行");
    }
🍍解决图片冗余问题

需求分析

  1. 家居图片都放在一个文件夹, 会越来越多
  2. 请尝试在assets/images/product-image/目录下, 自动创建年月日目录, 比如20230612. 以天为单位来存放上传图片
  3. 当上传新家居的图片, 原来的图片就没有用了, 应当删除原来的家居图片

工具类添加方法 - 返回当前日期

   public static String getYearMonthDay() {
       //第三代日期类
       LocalDateTime now = LocalDateTime.now();
       int year = now.getYear();
       int month = now.getMonthValue();
       int day = now.getDayOfMonth();
       String date = year + "/" + month + "/" + day + "/";
       return date;
   }

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

🍍分页导航完善

需求分析

  1. 如果总页数<=5, 就全部显示
  2. 如果总页数>5, 按照如下规则显示(这个规则由程序员/业务来决定)
    2.1 如果当前页是前3页, 就显示1-5
    2.2 如果当前页是后3页, 就显示最后5页
    2.3 如果当前页是中间页, 就显示 当前页前2页, 当前页, 当前页后2页

代码实现

<c:choose>
    <%--如果总页数<=5, 就全部显示--%>
    <c:when test="${requestScope.page.pageTotal <= 5}">
        <c:set scope="page" var="begin" value="1"></c:set>
        <c:set scope="page" var="end" value="${requestScope.page.pageTotal}"></c:set>
    </c:when>
    <%--如果总页数>5, 按照如下规则显示(这个规则由程序员/业务来决定)--%>
    <c:when test="${requestScope.page.pageTotal > 5}">
        <c:choose>
            <%--如果当前页是前3页, 就显示1-5--%>
            <c:when test="${requestScope.page.pageNo <= 3}">
                <c:set scope="page" var="begin" value="1"></c:set>
                <c:set scope="page" var="end" value="5"></c:set>
            </c:when>
            <%--如果当前页是后3页, 就显示最后5页--%>
            <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal - 3}">
                <c:set scope="page" var="begin" value="${requestScope.page.pageTotal - 4}"></c:set>
                <c:set scope="page" var="end" value="${requestScope.page.pageTotal}"></c:set>
            </c:when>
            <%--如果当前页是中间页, 就显示 当前页前2页, 当前页, 当前页后2页--%>
            <c:otherwise>
                <c:set scope="page" var="begin" value="${requestScope.page.pageNo - 2}"></c:set>
                <c:set scope="page" var="end" value="${requestScope.page.pageNo + 2}"></c:set>
            </c:otherwise>
        </c:choose>
    </c:when>
</c:choose>

🐀🐂🐅🐇🐉🐍🐎🐏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1865352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

flask水质监测预警系统-计算机毕业设计源码10148

摘 要 近些年来&#xff0c;对河道水位进行实时、准确的监测越来越受到广大人民群众的重视。然而要建立一个稳定的、可靠地、准确的城市河道水位远程监测系统&#xff0c;就必须要解决由人工监测向自动化监测的转变&#xff0c;使用新科技来进行设计。水质监测预警系统是以实际…

构筑卓越:建筑企业如何通过GB/T 50430:2017认证铸就质量管理基石

在建筑业这片充满挑战和机遇的战场上&#xff0c;企业资质犹如一面旗帜&#xff0c;标志着企业的实力和信誉。GB/T 50430:2017《工程建设施工企业质量管理规范》的实施&#xff0c;成为了建筑企业提高管理水平、赢得市场竞争的重要武器。 GB/T 50430:2017的战略意义 GB/T 5043…

【JavaScript】BOM编程

目录 一、BOM编程是什么 二、window对象的常用方法 1、弹窗API方法 2、计时器任务方法 三、window对象的属性对象常用方法 1、history网页浏览历史 2、location地址栏 3、数据存储属性对象 4、console控制台 一、BOM编程是什么 当我们使用浏览器打开一个网页窗口时&#xff0c;…

python f.write中文乱码怎么解决

举个例子&#xff1a; #coding:utf-8 s u中文 f open("test.txt","w") f.write(s) f.close() 原因是编码方式错误&#xff0c;应该改为utf-8编码。 解决方案一&#xff1a; #coding:utf-8 s u中文 f open("test.txt","w") f.writ…

新改进!LSTM与注意力机制结合,性能一整个拿捏住

众所周知&#xff0c;LSTM并不能很好地处理长序列和重要信息的突出&#xff0c;这导致在某些情况下性能不佳。而注意力机制模拟人类视觉注意力机制的特点可以很好地解决这个问题。 说具体点就是&#xff0c;注意力机制通过权重分布来决定应该关注输入序列中的哪些部分&#xf…

新需求:如何实现一个ShardingSphere分库分表平台

大家好&#xff0c;目前我们正面对一个既具挑战又令人兴奋的任务——构建一套高效、稳定的数据处理系统&#xff0c;特别是一个结合了SpringBoot、ShardingSphere、MyBatisPlus和MySQL技术的综合数据分库分表平台。简单来说&#xff0c;我们要做的就是打造一个能轻松应对大数据…

在Ubuntu上安装Python3

安装 python3 pip sudo apt -y install python3 python3-pip升级 pip python3 -m pip install --upgrade pip验证查看版本 python3 --version

#01算法的复杂性

时间复杂度 public void print(int n){int a 1; //执行1次for(int i0;i<n;i){//执行n次System.out.println(ai);//执行n次} } 该算法的时间复杂度是O(2n1) 大O会忽略常数、低阶和系数&#xff0c;最终记作O(n); 如果算法的执行时间和数据规模n无关&#xff0c;则是常量阶…

PR曲线(Precision-Recall Curve,精确率-召回率曲线)

PR曲线&#xff08;Precision-Recall Curve&#xff0c;精确率-召回率曲线&#xff09;是一种用于评估二分类模型性能的工具&#xff0c;特别适用于不平衡数据集。PR曲线通过绘制精确率&#xff08;Precision&#xff09;与召回率&#xff08;Recall&#xff09;之间的关系&…

Unity射击游戏开发教程:(30)如何让玩家追踪敌人

在本文中,我将介绍如何让敌人旋转跟随玩家并以相同的旋转发射射弹。我追求的行为是…… 当玩家移动时,敌人会旋转,因此它始终指向玩家。敌人将以恒定的速率发射射弹,并且射弹将以与敌人发射时相同的位置和旋转开始。

智能聊天AI机器人网页怎么聊?这样做很简单

智能聊天AI机器人网页怎么聊&#xff1f;随着科技的飞速发展&#xff0c;智能聊天AI机器人已经逐渐渗透到我们的日常生活中&#xff0c;为我们提供了更加便捷、高效的交流方式。在网页上&#xff0c;这些智能聊天机器人以其独特的魅力&#xff0c;为我们打开了与机器对话的新世…

Java数据脱敏

数据脱敏 敏感数据在存储过程中为是否为明文, 分为两种 落地脱敏: 存储的都是明文, 返回之前做脱敏处理不落地脱敏: 存储前就脱敏, 使用时解密, 即用户数据进入系统, 脱敏存储到数据库中, 查询时反向解密 落地脱敏 这里指的是数据库中存储的是明文数据, 返回给前端的时候脱…

# [0622] Task02 model-free 免模型类 RL 算法的预测和控制 【ε 贪心策略 优化的证明】

easy-rl PDF版本 笔记整理 P3 joyrl 比对 补充 P4 - P5 相关 代码 整理 ——> 有空 另开一页 最新版PDF下载 地址&#xff1a;https://github.com/datawhalechina/easy-rl/releases 国内地址(推荐国内读者使用)&#xff1a; 链接: https://pan.baidu.com/s/1isqQnpVRWbb3yh8…

Keka for Mac:轻量级压缩解压神器

Keka for Mac是一款专为Mac用户打造的轻量级压缩解压软件&#xff0c;凭借其强大的功能和简洁易用的界面&#xff0c;赢得了众多用户的喜爱。无论是日常办公还是学习娱乐&#xff0c;Keka都能为您提供高效、安全的文件压缩和解压体验。 Keka for Mac v1.4.2中文版下载 产品特点…

NAT和内网穿透

NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是一种广泛应用于计算机网络的技术&#xff0c;其主要目的是为了解决IPv4地址空间的短缺问题&#xff0c;并且增强网络安全。NAT技术允许一个私有网络内的多个设备共享一个或几个全局唯一的公共…

JavaEE之HTTP协议(1)_HTTP基础知识,HTTP 请求、响应格式,方法,状态码

一、HTTP协议 1.1 基本概念: HTTP全称超文本传输协议&#xff0c;是一种无状态的、应用层的协议&#xff0c;它基于请求/响应模型。客户端&#xff08;通常是Web浏览器&#xff09;通过发送HTTP请求到服务器来获取或发送信息&#xff0c;服务器则返回HTTP响应作为回应。HTTP协…

MySQL实训--原神数据库

原神数据库 er图DDL/DML语句查询语句存储过程/触发器 er图 DDL/DML语句 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;DROP TABLE IF EXISTS artifacts; CREATE TABLE artifacts (id int NOT NULL AUTO_INCREMENT,artifacts_name varchar(255) CHARACTER SET utf8 COLLATE …

宿主机无法通过ip连接wsl2解决方案

文章目录 原因排查网络模式win11防火墙关闭wsl ubuntu防火墙 如果之前能连接现在连接不上可以参考该方案 原因排查 网络模式win11防火墙(win11新增了Hyper-V防火墙)wsl2 ubuntu防火墙 网络模式 wsl2的默认网络模式是NAT&#xff0c;建议修改为镜像模式。在C:\Users\<User…

深入探讨极限编程(XP):技术实践与频繁发布的艺术

目录 前言1. 极限编程的核心原则1.1 沟通1.2 简单1.3 反馈1.4 勇气1.5 尊重 2. 关键实践2.1 结对编程2.1.1 提高代码质量2.1.2 促进知识共享2.1.3 增强团队协作 2.2 测试驱动开发&#xff08;TDD&#xff09;2.2.1 提升代码可靠性2.2.2 提高代码可维护性2.2.3 鼓励良好设计 2.3…

Volatility 内存取证【信安比赛快速入门】

一、练习基本命令使用 1、获取镜像信息 ./volatility -f Challenge.raw imageinfo 一般取第一个就可以了 2、查看用户 ./volatility -f Challenge.raw --profileWin7SP1x64 printkey -K "SAM\Domains\Account\Users\Names" 3、获取主机名 ./volatility -f Challenge…