Java进阶学习第十二天(监听器、国际化)

一、监听器

1、监听器(listener):主要是用来监听特定对象的创建或销毁、属性的变化的!是一个实现特定接口的普通java类!

2、对象:
自己创建自己用(不用监听)
别人创建自己用(需要监听)

3、Servlet中哪些对象需要监听?
request / session / servletContext
分别对应的是request监听器、session相关监听器、servletContext监听器

4、监听器接口
① 监听对象创建/销毁的监听器接口

Interface ServletRequestListener     //监听request对象的创建或销毁
Interface HttpSessionListener        //监听session对象的创建或销毁
Interface ServletContextListener     //监听servletContext对象的创建或销毁

② 监听对象属性的变化

Interface ServletRequestAttributeListener  //监听request对象属性变化: 添加、移除、修改
Interface HttpSessionAttributeListener     //监听session对象属性变化: 添加、移除、修改
Interface ServletContextAttributeListener  //监听servletContext对象属性变化: 添加、移除、修改

③ session相关监听器(了解)

Interface HttpSessionBindingListener      //监听对象绑定到session上的事件  
Interface HttpSessionActivationListener   //监听session序列化及反序列化的事件

5、生命周期监听器
① 声明周期监听器: 监听对象的创建、销毁的过程!
② 监听器开发步骤:
◆ 写一个普通java类,实现相关接口;
◆ 配置(web.xml)
总结:先写类,实现接口; 再配置
③ ServletRequestListener:监听request对象的创建或销毁
代码:

/**
 *  监听request对象的创建或销毁
 */
public class MyRequestListener implements ServletRequestListener{
    // 对象销毁
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // 获取request中存放的数据
        Object obj = sre.getServletRequest().getAttribute("cn");
        System.out.println(obj);
        System.out.println("MyRequestListener.requestDestroyed()");
    }

    // 对象创建
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("MyRequestListener.requestInitialized()");
    }
}

Web.xml:

<!-- 监听request对象创建、销毁 -->
    <listener>
        <listener-class>cn.itcast.a_life.MyRequestListener</listener-class>
    </listener>

④ HttpSessionListener:监听session对象的创建或销毁
代码:

/**
 * 监听Session对象创建、销毁
 */
public class MySessionListener implements HttpSessionListener{
    // 创建
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("MySessionListener.sessionCreated()");
    }

    // 销毁
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("MySessionListener.sessionDestroyed()");
    }
}

Web.xml:

<!-- 监听session对象创建、销毁 -->
    <listener>
        <listener-class>cn.itcast.a_life.MySessionListener</listener-class>
    </listener>

⑤ ServletContextListener:监听servletContext对象的创建或销毁
代码:

/**
 * 监听ServletContext对象创建或销毁
 */
public class MyServletContextListener implements ServletContextListener{
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyServletContextListener.contextDestroyed()");
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("1..........MyServletContextListener.contextInitialized()");
    }
}

Web.xml:

<!-- 监听servletContext对象创建、销毁 -->
    <listener>
        <listener-class>cn.itcast.a_life.MyServletContextListener</listener-class>
    </listener>

6、属性监听器
其中一个:HttpSessionAttributeListener

/**
 * 监听session对象属性的变化
 */
public class MySessionAttrListener implements HttpSessionAttributeListener {
    // 属性添加
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        // 先获取session对象
        HttpSession session = se.getSession();
        // 获取添加的属性
        Object obj = session.getAttribute("userName");
        // 测试
        System.out.println("添加的属性:" + obj);
    }
    // 属性移除
    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("属性移除");
    }
    // 属性被替换
    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        // 获取sesison对象
        HttpSession session = se.getSession();
        // 获取替换前的值
        Object old = se.getValue();
        System.out.println("原来的值:" + old);
        // 获取新值
        Object obj_new = session.getAttribute("userName");
        System.out.println("新值:" + obj_new);    
    }
}
<!-- 属性监听器 -->
    <listener>
        <listener-class>cn.itcast.b_attr.MySessionAttrListener</listener-class>
    </listener>

7、其他监听器: session相关监听器
HttpSessionBindingListener:监听对象绑定/解除绑定到sesison上的事件

步骤:对象实现接口,再把对象绑定/解除绑定到session上就会触发监听代码
作用:上线提醒!

/**
 * 监听此对象绑定到session上的过程,需要实现session特定接口
 */
public class Admin implements HttpSessionBindingListener {
    private int id;
    private String name;
    public Admin() {
        super();
    }
    public Admin(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    // 构造函数
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    // 对象放入session
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("Admin对象已经放入session");
    }
    // 对象从session中移除
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("Admin对象从session中移除!");
    }
}

思考:这个session监听器,和上面的声明周期、属性监听器区别?
◆ 不用再web.xml配置
◆ 因为监听的对象是自己创建的对象,不是服务器对象!

8、案例
① 需求:做一个在线列表提醒的功能
用户登陆 > 显示登陆信息,列表展示(list.jsp) > 显示在线用户列表(list.jsp) > 列表点击进入“在线列表页面”(onlineuser.jsp)
② 实现:
◆ 先增加退出功能; 再把session活跃时间设置为1min
◆ 写监听器,监听servletContext对象的创建:初始化集合(onlineuserlist)
◆ 登陆功能: 用户登陆时候,把数据保存到servletContext中
◆ List.jsp 增加超链接, 点击时候提交直接跳转到online.jsp
◆ 写监听器: 监听session销毁,把当前登陆用户从onlineuserlist移除

/**
 * 初始化在线列表集合监听器 
 */
public class OnlineAdminListener implements ServletContextListener {
    //1. ServletContext对象创建
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 创建集合:存放在线用户
        // 每次当用户登陆后,就往这个集合中添加添加当前登陆者
        List<Admin> onlineList = new ArrayList<Admin>();
        // 放入ServletContext中
        sce.getServletContext().setAttribute("onlineList", onlineList);
    }

    //2. ServletContext对象销毁
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // 获取ServletContext
        ServletContext sc = sce.getServletContext();
        // 获取在线列表
        Object obj = sc.getAttribute("onlineList");
        // 移除在线列表集合
        if (obj != null) {
            sc.removeAttribute("onlineList");
        }
    }
}
/**
 * 监听Session销毁的动作:
 *  当服务器销毁session的时候,从在线列表集合中移除当前的登陆用户
 */
public class SessionListener implements HttpSessionListener{
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        //1. 获取Session对象、ServletContext对象
        HttpSession session = se.getSession();
        ServletContext sc = session.getServletContext();
        //2. 获取Session中存储的当前登陆用户
        Object obj = session.getAttribute("loginInfo");//?
        //3. 获取ServletContext中存储的在线用户列表集合
        List<Admin> list = (List<Admin>) sc.getAttribute("onlineList");
        // 先判断
        if (obj != null){
            //4. 把“当前登陆用户”从在线列表集合中移除
            list.remove(obj);
        }
    }

    @Override
    public void sessionCreated(HttpSessionEvent se) {
    }
}

二、国际化

1、Javaweb增强:过滤器、监听器、国际化、文件上传下载、javaMail

2、国际化又简称为:i18n:internationalization

3、软件的国际化
软件:
① 在中国: 显示中文,以及服务符合中国习惯的文本字符串!
② 在美国: 显示英文,以及服务符合他国习惯的文本字符串!
这种软件,就叫国际化的软件!

4、如何做到国际化的软件,要求
① 软件中存储特定的字符串
② 知道浏览器当前使用哪种语言(Locale类)

5、Locale:本地化
Java提供了一个本地化的对象,封装当前语言、国家、环境等特征!

public class App {

    @Test
    //1. 本地化对象:Locale
    // 封装语言、国家信息的对象,由java.util提供
    public void testLocale() throws Exception {
        // 模拟中国语言等环境
        //Locale locale = Locale.CHINA;
        Locale locale = Locale.getDefault();            // 当前系统默认的语言环境
        System.out.println(locale.getCountry());        // CN:国家的简称
        System.out.println(locale.getDisplayCountry()); // 国家名称
        System.out.println(locale.getLanguage());       // zh:语言简称  
        // 模拟美国国家
        Locale l_us = Locale.US;
        System.out.println(l_us.getCountry());
        System.out.println(l_us.getDisplayCountry());
    }
}

6、国际化
① 静态数据国际化:网站中显示的固定文本的国际化(“用户名”“密码“)
② 动态文本国际化
中文:1987-09-19 ¥1000
英文: Sep/09 1987 $100

7、国际化的软件
① 存储所有国家显示的文本的字符串
◆文件:properties
◆ 命名:基础名_语言简称_国家简称.properties
例如:msg_zh_CN.properties :存储所有中文
Msg_en_US.properties:存储所有英文
② 程序中获取
ResourceBundle类,可以读取国际化的资源文件
③ 数值,货币,时间,日期等数据由于可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。Java 中提供了解决这些问题的 API 类(位于 java.util 包和 java.text 包中)

    // 国际化 - 静态数据
    @Test
    public void testI18N() throws Exception {   
        // 中文语言环境
        Locale locale = Locale.CHINA;   
        // 创建工具类对象ResourceBundle
        ResourceBundle bundle = ResourceBundle.getBundle("cn.itcast.f_i18n.msg", locale);
        // 根据key获取配置文件中的值
        System.out.println(bundle.getString("hello"));
        System.out.println(bundle.getString("username"));
        System.out.println(bundle.getString("pwd"));        
    }

    // 国际化 - 动态文本 - 0. 概述
    @Test
    public void testI18N2() throws Exception {
        // 国际化货币
        NumberFormat.getCurrencyInstance();
        // 国际化数字
        NumberFormat.getNumberInstance();
        // 国际化百分比
        NumberFormat.getPercentInstance();  
        // 国际化日期
        //DateFormat.getDateTimeInstance(dateStyle, timeStyle, aLocale)
    }

    // 国际化 - 动态文本 - 1. 国际化货币
    @Test
    public void testI18N3() throws Exception {
        // 模拟语言环境
        Locale locale = Locale.US;
        // 数据准备
        double number = 100;
        // 工具类
        NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
        // 国际化货币
        String m = nf.format(number);
        // 测试
        System.out.println(m);
    }

    //面试题:  代码计算:  $100 * 10  
    @Test
    public void eg() throws Exception {
        String str = "$100";
        int num = 10;       
        // 1. 分析str值是哪一国家的货币
        Locale us = Locale.US;
        // 2. 国际化工具类
        NumberFormat nf = NumberFormat.getCurrencyInstance(us);
        // 3. 解析str货币
        Number n = nf.parse(str);       
        System.out.println(n.intValue() * num);
    }

    // 国际化 - 动态文本 - 2. 国际化数值
    @Test
    public void testI18N4() throws Exception {
        // 模拟语言环境
        Locale locale = Locale.CHINA;
        NumberFormat nf = NumberFormat.getNumberInstance(Locale.CHINA);
        String str = nf.format(1000000000);
        System.out.println(str);
    }

    // 国际化 - 动态文本 - 3. 国际化日期
    /*
     * 日期:
     *    FULL   2018年9月11日 星期二
     *    LONG   2018年9月11日
     *    FULL   2018年9月11日 星期二
     *    MEDIUM 2018-9-11
     *    SHORT  18-9-11  
     * 时间:
     *    FULL   下午02时31分59秒 CST
     *    LONG   下午02时32分37秒
     *    MEDIUM 14:33:00
     *    SHORT  下午2:33 
     */
    @Test
    public void testI18N5() throws Exception {  
        // 日期格式
        int dateStyle = DateFormat.SHORT;
        // 时间格式
        int timeStyle = DateFormat.SHORT;   
        // 工具类
        DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.CHINA);     
        String date = df.format(new Date());
        System.out.println(date);
    }

    // 面试2: 请将时间值:09-11-28 上午10时25分39秒 CST,反向解析成一个date对象。
    @Test
    public void eg2() throws Exception {
        String str = "09-11-28 上午10时25分39秒 CST";
        // 创建DateFormat工具类,国际化日期
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL, Locale.getDefault());
        Date d = df.parse(str);
        System.out.println(d);
    }

8、Jsp页面国际化

<html>
  <head>
    <%
    ResourceBundle bundle = ResourceBundle.getBundle("cn.itcast.f_i18n.msg",request.getLocale());
    %>
    <title><%=bundle.getString("title") %></title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>

  <body>
  <form name="frmLogin" action="${pageContext.request.contextPath }/admin?method=login" method="post">
    <table align="center" border="1">
        <tr>
            <td><%=bundle.getString("username") %></td>
            <td>
                <input type="text" name="userName">
            </td>
        </tr>
        <tr>
            <td><%=bundle.getString("pwd") %></td>
            <td>
                <input type="password" name="pwd">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="<%=bundle.getString("submit") %>">
            </td>
        </tr>
    </table>
  </form>
  </body>
</html>

9、Jsp页面国际化 – 使用jstl标签(fmt.tld
JSTL标签(核心标签库、国际化与格式化标签库、数据库标签库(没用)、函数库)

<fmt:setLocale value=""/>        //设置本地化对象
<fmt:setBundle basename=""/>     //设置工具类
<fmt:message></fmt:message>      //显示国际化文本
//格式化数值(格式:0.00 保留两位小数,会自动补零;#.## 保留两位小数,不会自动补零)
<fmt:formatNumber pattern="#.##" value="100.99"></fmt:formatNumber>
//格式化日期
<fmt:formatDate pattern="yyyy-MM-dd" value="<%=new Date() %>"/>
<html>
  <head>
    <!-- 一、设置本地化对象 -->
    <fmt:setLocale value="${pageContext.request.locale}"/>
    <!-- 二、设置工具类 -->
    <fmt:setBundle basename="cn.itcast.f_i18n.msg" var="bundle"/>

    <title><fmt:message key="title" bundle="${bundle}"></fmt:message></title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>

  <body>
  <form name="frmLogin" action="${pageContext.request.contextPath }/admin?method=login" method="post">
    <table align="center" border="1">
        <tr>
            <td><fmt:message key="username" bundle="${bundle}"></fmt:message></td>
            <td>
                <input type="text" name="userName">
            </td>
        </tr>
        <tr>
            <td><fmt:message key="pwd" bundle="${bundle}"></fmt:message></td>
            <td>
                <input type="password" name="pwd">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="<fmt:message key="submit" bundle="${bundle}"/>">
            </td>
        </tr>
    </table>
  </form>
  </body>
</html>

猜你喜欢

转载自blog.csdn.net/Mr_GaoYang/article/details/82595782