栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JavaWeb学习笔记(9)-B站尚硅谷

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaWeb学习笔记(9)-B站尚硅谷

文章目录
  • 二十二、书城项目第八阶段
    • 001-使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查
    • 002-ThreadLocal的使用
    • 003-使用 Filter 和 ThreadLocal 组合管理事务
      • (1)使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成
      • (2)使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch,来进行事务的管理
      • (3)将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息
  • 二十三、JSON
    • 001-什么是JSON
    • 002-JSON在JavaScript中的使用
      • (1)JSON的定义
      • (2)JSON的访问
      • (3)JSON的两个常用方法
    • 003-JSON在Java中的使用
      • (1)javaBean 和 json 的互转
      • (2)List 和 json 的互转
      • (3)map 和 json 的互转
  • 二十四、AJAX请求
    • 001-什么是AJAX请求?
    • 002-原生AJAX请求示例
    • 003-jQuery中的Ajax请求
  • 二十五、书城项目第九阶段
    • 001-使用 AJAX 验证用户名是否可用
    • 002-使用 AJAX修改 把商品添加到购物车
  • 二十六、i18n国际化(了解内容)
    • 001-什么是 i18n 国际化
    • 002-国际化相关要素介绍
    • 003-国际化资源 properties 测试
    • 004-通过请求头国际化页面
    • 005-JSTL 标签库实现国际化

二十二、书城项目第八阶段 001-使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查
通过Filter拦截/pages/manager/下的所有内容,只有用户登录之后,才能访问。
即 点击后台管理 只有用户登录之后才能进入后台。

在src/com.atguigu/下创建一个package--->filter
在filter下创建ManagerFilter进行拦截
package com.atguigu.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class ManagerFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对pages/manager/下的所有内容进行拦截,只有登录之后才能访问
        //即登录之后,才能进入后台管理

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

        Object user = httpServletRequest.getSession().getAttribute("user");

        if (user == null) {
            //如果user为空,即用户未登录,跳转到登录页面
            httpServletRequest.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletResponse);
        } else {
            //用户登录了,则不拦截
            filterChain.doFilter(servletRequest,servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

002-ThreadLocal的使用

这个大致看看理解一下就好了,看003

ThreadLocal中保存的数据,在线程销毁后,会由JVM虚拟机自动释放。
public class OrderService {
	public void createOrder(){
		String name = Thread.currentThread().getName();
		System.out.println("OrderService 当前线程[" + name + "]中保存的数据是:" + ThreadLocalTest.threadLocal.get());
		new OrderDao().saveOrder();
	}
}

public class OrderDao {
	public void saveOrder(){
		String name = Thread.currentThread().getName();
		System.out.println("OrderDao 当前线程[" + name + "]中保存的数据是:" + ThreadLocalTest.threadLocal.get());
	}
}

public class ThreadLocalTest {
	// public static Map data = new Hashtable();
	public static ThreadLocal threadLocal = new ThreadLocal();
	private static Random random = new Random();
	
	public static class Task implements Runnable {
	
		@Override
		public void run() {
			// 在 Run 方法中,随机生成一个变量(线程要关联的数据),然后以当前线程名为 key 保存到 map 中
			Integer i = random.nextInt(1000);
			// 获取当前线程名
			String name = Thread.currentThread().getName();
			System.out.println("线程["+name+"]生成的随机数是:" + i);
			// data.put(name,i);
			threadLocal.set(i);
		
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			new OrderService().createOrder();
			// 在 Run 方法结束之前,以当前线程名获取出数据并打印。查看是否可以取出操作
			// Object o = data.get(name);
			Object o = threadLocal.get();
			System.out.println("在线程["+name+"]快结束时取出关联的数据是:" + o);
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 3; i++){
			new Thread(new Task()).start();
		}
	}
}
 
003-使用 Filter 和 ThreadLocal 组合管理事务 
(1)使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成 

希望 订单的生成,订单项的生成,和图书的销量和库存的变化,要么同时成功,要么同时失败。
因为有时会出现订单生成但订单项未生成等情况。
这就涉及到数据库的事务问题。


OrderServlet,OrderServiceImpl,OrderDaoImpl,BaseDao,BookDaoImpl,OrderItemDaoImpl都在同一个线程中执行。

所有获取的连接对象Connection,都可以使用ThreadLocal创建的同一个对象。这样就实现了在同一个线程内执行。

JdbcUtils 工具类的修改:
	添加了Thread
	getConnection()方法修改了
	原来的close()方法删除了
	新增了commitAndClose()方法和rollbackAndClose()方法
	最后Connection连接关闭了,但是ResultSet和PreparedStatement资源没关。不知道为什么
package com.atguigu.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class JdbcUtils {
    //获取数据库连接池中的连接
    private static DruidDataSource dataSource;

    private static ThreadLocal conns = new ThreadLocal();

    static {
        try {
            Properties properties = new Properties();
            //从流中加载数据
            //这里路径要写成绝对路径
            properties.load(new FileInputStream("E:\IDEA\Projects\JavaWeb-BzhanTeach\09-书城项目第二阶段\src\druid.properties"));

            //创建数据库连接池
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //返回null 获取连接失败
    public static Connection getConnection(){
        Connection conn = conns.get();

        if (conn == null){
            try {
                conn = dataSource.getConnection();//从数据库连接池中获取连接

                conns.set(conn);//保存到ThreadLocal对象中,供后面的jdbc操作使用

                conn.setAutoCommit(false);//设置为手动管理事务

            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return conn;
    }

    

    //提交事务,并关闭释放连接
    public static void commitAndClose(){
        Connection conn = conns.get();

        if (conn != null){//不等于null 说明之前使用过连接,操作过数据库
            try {
                conn.commit();//提交事务
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                try {
                    conn.close();//关闭连接,释放资源
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        //一定要执行remove操作,否则会出错。(因为Tomcat底层使用了线程池)
        //web中的线程是重复使用,remove是为保证下次线程得不到上一次线程在ThreadLocal中set的值
        conns.remove();
    }

    //回滚事务,并关闭释放连接
    public static void rollbackAndClose(){
        Connection conn = conns.get();

        if (conn != null){//不等于null 说明之前使用过连接,操作过数据库
            try {
                conn.rollback();//回滚事务
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                try {
                    conn.close();//关闭连接,释放资源
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        conns.remove();
    }
}

testJdbcUtils不需要了,可删去。
修改BaseDao:
	所有的finally和关闭连接都删去,不需要写了(因为如果在这里关闭连接了,后面的相关程序就获取不到连接了)
	把所有的捕捉异常都改为上抛异常(因为如果在这里就把异常捕捉了,后面就捕捉不到异常了)或者在catch里面使用 throw new RuntimeExceptioon(e); 同时删去最后的return
package com.atguigu.dao;

import com.atguigu.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public abstract class BaseDao {

    //使用DBUtils操作数据库
    private QueryRunner queryRunner = new QueryRunner();

    
    public int update(String sql, Object... args){
        Connection conn = JdbcUtils.getConnection();

        try {
            return queryRunner.update(conn,sql,args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e); //上抛异常
        }
    }

    
    public  T queryForOne(Class type, String sql, Object... args){
        Connection conn = JdbcUtils.getConnection();

        try {
            return queryRunner.query(conn, sql, new BeanHandler(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e); //上抛异常
        }
    }

    
    public  List queryForList(Class type, String sql, Object... args){
        Connection conn = JdbcUtils.getConnection();

        try {
            return queryRunner.query(conn, sql, new BeanListHandler(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e); //上抛异常
        }
    }

    //针对返回一列一行的sql语句(针对 select count(*) from 表名)(针对 count(*) 这样的函数)
    public Object queryForSingleValue(String sql, Object... args){
        Connection conn = JdbcUtils.getConnection();

        try {
            return queryRunner.query(conn, sql, new ScalarHandler(), args);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e); //上抛异常
        }
    }
}

捕获OrderServlet程序中的OrderService.createOrder()方法中的异常:
这个看看就好,先别写,往下看。

(2)使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch,来进行事务的管理
有很多Service方法,不可能一个一个加try...catch
通过给 filterChain.doFilter()添加try...catch就相当于给所有的Service方法都添加了try...catch
因为filterChain.doFilter()方法的作用之一会调用Servlet程序(也就是会使用其中的Service方法)

在filter package下创建 TransactionFilter:
package com.atguigu.filter;

import com.atguigu.utils.JdbcUtils;

import javax.servlet.*;
import java.io.IOException;

public class TransactionFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        try {
            filterChain.doFilter(servletRequest, servletResponse);
            JdbcUtils.commitAndClose(); // 提交事务 关闭连接
        }catch (Exception e){
            JdbcUtils.rollbackAndClose(); // 回滚事务 关闭连接
            e.printStackTrace();
        }
    }

    @Override
    public void destroy() {

    }
}



dao层,service层和web层的servlet出现异常都要抛出,在doFilter()方法中捕获异常一起解决

(3)将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息

如果发生异常,在页面展示出友好的错误信息

在 web.xml 中我们可以通过错误页面配置来进行管理。

新建目录pages/error
在error目录下新建 error404.jsp error500.jsp
为发生异常时显示的页面


注意:TransactionFilter的doFilter方法中要把异常抛给Tomcat,否则无法显示异常信息,因为doFilter方法中已经把异常抓到了。

二十三、JSON 001-什么是JSON

002-JSON在JavaScript中的使用 (1)JSON的定义
json 是由键值对组成,并且由花括号(大括号)包围。
每个键由引号引起来,键和值之间使用冒号进行分隔,多组键值对之间进行逗号进行分隔。

json 定义示例:



    
    Title
    





(2)JSON的访问
json 本身是一个对象。
json 中的 key 我们可以理解为是对象中的一个属性。
json 中的 key 访问就跟访问对象的属性一样: json 对象.key

json 访问示例:



    
    Title
    





(3)JSON的两个常用方法
json 的存在有两种形式:
	一种是:对象的形式存在,我们叫它 json 对象。
	一种是:字符串的形式存在,我们叫它 json 字符串。
	
	JSON.stringify() 	把 json 对象转换成为 json 字符串
	JSON.parse() 		把 json 字符串转换成为 json 对象
		
一般我们要操作 json 中的数据的时候,需要 json 对象的格式。
一般我们要在客户端和服务器之间进行数据交换的时候,使用 json 字符串。



    
    Title
    





003-JSON在Java中的使用

JSON在服务器的使用(客户端与服务器端数据的交换格式)

首先要添加jar包gson-2.2.4.jar
在WEB-INF下创建lib目录,将jar包添加进去,记得add as library

Person类:
package com.atguigu.bean;

public class Person {

    private Integer id;
    private String name;

    public Person() {
    }

    public Person(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + ''' +
                '}';
    }
}
(1)javaBean 和 json 的互转
package com.atguigu.json;

import com.atguigu.bean.Person;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;

public class JsonTest {
    @Test
    public void test1(){
        Person person = new Person(1,"国哥好帅!");

        // 创建 Gson 对象实例
        Gson gson = new Gson();

        // toJson 方法可以把 java 对象转换成为 json 字符串
        String personJsonString = gson.toJson(person);
        System.out.println(personJsonString);

        // fromJson 把 json 字符串转换回 Java 对象
        // 第一个参数是 json 字符串
        // 第二个参数是转换回去的 Java 对象类型
        Person person1 = gson.fromJson(personJsonString, Person.class);
        System.out.println(person1);
    }
}

(2)List 和 json 的互转
fromJson(String Json, Class classOfT) ---> json与javabean互转时使用这个
fromJson(String Json, Type typeOf) ---> json 与 集合 互转时使用这个
package com.atguigu.json;

import com.atguigu.bean.Person;
import com.google.gson.reflect.TypeToken;

import java.util.List;

// List 或 ArrayList 都可以
public class PersonListType extends TypeToken>{
    //这个类什么都不用写
    //只用写这个类继承 TypeToken,然后把 json要转换为的类型的泛型放进去即可
}

package com.atguigu.json;

import com.atguigu.bean.Person;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

public class JsonTest {
    @Test
    // List 与 json 互转
    public void test2() {
        List personList = new ArrayList<>();

        personList.add(new Person(1, "国哥"));
        personList.add(new Person(2, "康师傅"));

        Gson gson = new Gson();

        // 把 List 转换为 json 字符串
        String personListJsonString = gson.toJson(personList);
        System.out.println(personListJsonString);

        // 把 json 字符串 转换为 List
        // gson.fromJson(personListJsonString, personList.getClass()写这个不行)
        List list = gson.fromJson(personListJsonString, new PersonListType().getType());

        System.out.println(list);

        Person person = list.get(0);
        System.out.println(person);
    }
}
(3)map 和 json 的互转
package com.atguigu.json;

import com.atguigu.bean.Person;
import com.google.gson.reflect.TypeToken;

import java.util.Map;

// Map 或 HashMap 都可以
public class PersonMapType extends TypeToken> {
}
package com.atguigu.json;

import com.atguigu.bean.Person;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonTest {
    @Test
    // map 与 json 互转
    public void test3(){
        Map personMap = new HashMap<>();
        personMap.put(1, new Person(1, "国哥好帅"));
        personMap.put(2, new Person(2, "康师傅也好帅"));

        Gson gson = new Gson();

        // 把 map 集合转换成为 json 字符串
        String personMapJsonString = gson.toJson(personMap);
        System.out.println(personMapJsonString);

        // 把 json 转换为 map
        Map personMap2 = gson.fromJson(personMapJsonString, new PersonMapType().getType());

        System.out.println(personMap2);

        Person p = personMap2.get(1);
        System.out.println(p);
    }
}
如果json与集合互转,会产生很多空的类,比如:PersonListType和PersonMapType
可以使用匿名内部类的方法,这样就不用写空类了。
即使用 Map personMap2 = gson.fromJson(personMapJsonString, new TypeToken>(){}.getType());
替换 Map personMap2 = gson.fromJson(personMapJsonString, new PersonMapType().getType()); 和删除对应的空类
二十四、AJAX请求 001-什么是AJAX请求?
AJAX 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。

ajax 是一种浏览器通过 js 异步发起请求,局部更新页面的技术。
	Ajax 请求的局部更新,浏览器地址栏不会发生变化
	局部更新不会舍弃原来页面的内容

	同步:下一个程序的执行 要等到上一个程序执行结束之后 才能执行
	异步:类似于多线程并发,下一个程序的执行 不需要等待 上一个程序的执行完成,会直接执行
002-原生AJAX请求示例

ajax.html:



    
    Title
    


    
    



003-jQuery中的Ajax请求

一般不会使用原生的ajax,而是使用jQuery框架来使用ajax

$.ajax 方法:五个参数
	url 表示请求的地址
	type 表示请求的类型 GET 或 POST 请求
	data 表示发送给服务器的数据
		格式有两种:
		一:name=value&name=value
		二:{key:value}
		
	success 请求成功,响应的回调函数
	
	dataType 响应的数据类型
		常用的数据类型有:
			text 表示纯文本
			xml 表示 xml 数据
			json 表示 json 对象



    
    Title
    
    


    


用户名:
密码:
下拉单选:
下拉多选:
复选: check1 check2
单选: radio1 radio2


$.get 方法和$.post 方法(是对$.ajax的进一步封装):4个参数
	url 请求的 url 地址
	data 发送的数据
	callback 成功的回调函数
	type 返回的数据类型



$.getJSON 方法(通过get请求 返回json类型的数据):
	url 请求的 url 地址
	data 发送给服务器的数据
	callback 成功的回调函数



表单序列化 serialize()
serialize()可以把表单中所有表单项的内容都获取到,
	并以 name=value&name=value 



Ajax 可以在页面中局部更新,不再需要跳转页面

二十五、书城项目第九阶段 001-使用 AJAX 验证用户名是否可用

首先将gson jar包添加到书城项目下


原来写的验证用户名是否可用 不用删除,因为那是点击注册之后验证的。
而这里的ajax是在点击验证之前,输入用户名 焦点消失之后就立刻验证。
002-使用 AJAX修改 把商品添加到购物车

修改CartServlet:

原来的加入购物车功能实现:

使用ajax实现加入购物车功能:

二者的区别只是在最后不同,其他的都一样:原来的是重定向到指定页面,而现在不需要跳转页面。


修改pages/client/index.jsp:



二十六、i18n国际化(了解内容) 001-什么是 i18n 国际化

002-国际化相关要素介绍

003-国际化资源 properties 测试



004-通过请求头国际化页面

对页面,表单进行国际化

第一种:在浏览器的设置中 设置页面的语言
<%@ page import="java.util.Locale" %>
<%@ page import="java.util.ResourceBundle" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


<%
    // 从请求头中获取 Locale 信息(语言)
    Locale locale = request.getLocale();
    System.out.println(locale);
    
    // 获取读取包(根据 指定的 baseName 和 Locale 读取 语言信息)
    ResourceBundle i18n = ResourceBundle.getBundle("i18n", locale);
%>
中文|
english

<%=i18n.getString("regist")%>

<%=i18n.getString("username")%>
<%=i18n.getString("password")%>
<%=i18n.getString("sex")%> <%=i18n.getString("boy")%> <%=i18n.getString("girl")%>
<%=i18n.getString("email")%>
" />   " />




国际化测试:
1、访问页面,通过浏览器设置,请求头信息确定国际化语言。
2、通过左上角,手动切换语言

第二种:点击左上方的语言进行语言切换

<%@ page import="java.util.Locale" %>
<%@ page import="java.util.ResourceBundle" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


<%
	// 从请求头中获取 Locale 信息(语言)
	Locale locale = null;
	String country = request.getParameter("country");
	
	if ("cn".equals(country)) {
		locale = Locale.CHINA;
	} else if ("usa".equals(country)) {
		locale = Locale.US;
	} else {
		locale = request.getLocale();
	}
	System.out.println(locale);
	
	// 获取读取包(根据 指定的 baseName 和 Locale 读取 语言信息)
	ResourceBundle i18n = ResourceBundle.getBundle("i18n", locale);
%>
中文|
english

<%=i18n.getString("regist")%>

<%=i18n.getString("username")%>
<%=i18n.getString("password")%>
<%=i18n.getString("sex")%> <%=i18n.getString("boy")%> <%=i18n.getString("girl")%>
<%=i18n.getString("email")%>
" />   " />




国际化测试:
1、访问页面,通过浏览器设置,请求头信息确定国际化语言。
2、通过左上角,手动切换语言
005-JSTL 标签库实现国际化

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>


	Insert title here


	<%--1 使用标签设置 Locale 信息--%>
	
	<%--2 使用标签设置 baseName--%>
	
	
	中文|
	english
	
	

" />   " />




转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号