美文网首页
ThreadLocal

ThreadLocal

作者: _FireFly_ | 来源:发表于2019-10-27 19:21 被阅读0次
    登录效果
        ---->index.jsp
        index.jsp资源
        输入账号
        输入密码
        点击登录---->login
    
        LoginController
        获取请求传递的账号和密码
        找寻业务层处理
        根据登录结果String给予响应
    
        welcome.jsp
        欢迎xx进入系统    xx---昵称
            1.在service层中添加一个新的方法   专门获取昵称
                登录(查询)     昵称(查询)   影响性能问题
            2.在service层原有的登录方法上进行修改
                返回值改为user对象(保证业务的判断放在service里)
                返回值修改之后   之前的使用习惯有影响
    
    ThreadLocal
    
            1.将所有的资源部署在tomcat上  war包
            2.启动tomcat  带着这些资源一起运行
    
    3.浏览器发送请求
    请求(资源)----> tomcat解析请求    寻找资源(参考配置文件)    html   jsp   servlet
        带着参数        找到一个servlet request.getParameter
                将参数传递给service
                service将参数传递给dao
                dao传递参数给JDBC 负责拼接 SQL
                将SQL发送给数据库   执行sql  update  query
    
                数据库查询的结果ResultSet
                交给JDBC(ORM) 将ResultSet拆开  变成对象domain
                dao接收JDBC的返回值   交给Service
                Service调用dao的方法  获取方法返回值(对象 集合)
                Service将返回值拆开  做业务判断  将结果返回给Controller
                controller做转发(带着service的返回值)
        浏览器解析响应
        最终展示
    
        参数浏览器触发通常通过方法传递参数的形式进去的
        数据得到的查询结果通常通过方法返回值形式出来的
    
    V:  View视图层 HTML(静态信息)+JSP(动态信息)   信息(String)
            JSP(HTML标签+EL+JSTL+JS+CSS)      EL取值拼接----响应
    C:  Controller控制层   控制的是信息  Servlet     setAttribute(结果);
            Servlet(获取请求参数+调用业务+给予响应 转发 重定向 自己给)
            通过request接收参数  传递给业务        返回值(业务判断结果)
    M:  Model模型层    数据模型(数据处理+数据读写+数据存储)
            Service数据处理 业务逻辑            domain对象(不通过返回值)
            接收方法参数的传递  传递给dao
            Dao     数据读写         存储CURD         ResultSet拆成对象
            接收方法参数的传递  传递给JDBC(ORM) 拼串儿SQL  ResultSet返回值
            Domain数据存储       一行记录--一个对象
    DB: DataBase数据层
            MySQL
    
    
    session对象的管理类
    SessionManager{//Tomcat内部的 看不见  sessionMap是单例
    private Map<JSESSIONID,HttpSession> sessionMap; 
    public HttpSession getSession(String JSESSIONID){   
        return sessionMap.get(JSESSIONID);      
    }
    }
    使用的session类 好多个session对象    每一个对象一个人使用
    HttpSession{
    private Map<String key,Object value> attributeMap;
    public Object getAttribute(String key){
        return attributeMap.get(key);
    }
    public void setAttribute(String key,Object value){
        attributeMap.put(key,value);
    }
    }
    
    
    JSESSIONID(String 标识)-------------> t 当前线程(Thread类型 标识)
    通过标识找session(一个箱子)---------->通过t找ThreadLocalMap(一个箱子)
    通过session.setAttribute(key,value);  ThreadLocalMap.set(this,value);
    key自己定义     key已经固定了    this当前对象(ThreadLocal)
    
                我是一个线程t   t本身是找箱子的密码
                t负责找到我的箱子ThreadLocalMap
                这个箱子只有一个格子
                找到箱子打开才能获取里面的value  
                打开箱子需要另一个密码(ThreadLocal对象)
                当前t线程配着一个Threadlocal对象  map就是唯一的
                value只能存储一个信息 想要存储多个  将多个信息包装起来
    
                Thread
                ThreadLocal
                ThreadLocalMap(ThreadLocal的内部类)
    

    我们可以通过ThreadLocal来将service的数据保存起来,然后在页面中取出来

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <servlet>
            <servlet-name>login</servlet-name>
            <servlet-class>controller.LoginController</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>login</servlet-name>
            <url-pattern>/login</url-pattern>
        </servlet-mapping>
    </web-app>
    

    工具类:MySpring

    package util;
    
    import java.util.HashMap;
    
    public class MySpring {
    
        private static HashMap<String,Object> beanMap = new HashMap<String,Object>();
    
        public static <T>T getBean(String className){
            T obj = (T)beanMap.get(className);
            if(obj==null){
                try {
                    Class clazz = Class.forName(className);
                    obj = (T)clazz.newInstance();
                    beanMap.put(className,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return obj;
        }
    }
    

    工具类:ThreadLocalManager

    package util;
    
    import java.util.HashMap;
    
    public class ThreadLocalManager {
    
        //管理不同的ThreadLocal对象    一个人分配一个ThreadLocal
        //用每一个人登录的账号作为key   每一个ThreadLocal对象作为值
        private static HashMap<String,ThreadLocal> localMap = new HashMap<>();
    
        //通过登录账号获取自己对应的那一个local对象
        public static ThreadLocal getThreadLocal(String name){
            ThreadLocal local = localMap.get(name);
            if(local==null){
                local = new ThreadLocal();
                localMap.put(name,local);
            }
            return local;
        }
    
    }
    
    

    index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <body>
        <form action="login" method="post">
          账号:<input type="text" name="uname" value=""><br>
          密码:<input type="password" name="upassword" value=""><br>
          <input type="submit" value="登录"><br>
        </form>
      </body>
    </html>
    

    User

    package domain;
    
    public class User {
    
        private String uname;
        private String upassword;
        private String nickname;
    
        public User() {
        }
    
        public User(String uname, String upassword,String nickname) {
            this.uname = uname;
            this.upassword = upassword;
            this.nickname = nickname;
        }
    
        public String getUname() {
            return uname;
        }
    
        public void setUname(String uname) {
            this.uname = uname;
        }
    
        public String getUpassword() {
            return upassword;
        }
    
        public void setUpassword(String upassword) {
            this.upassword = upassword;
        }
    
        public String getNickname() {
            return nickname;
        }
    
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    }
    
    

    LoginController

    package controller;
    
    import domain.User;
    import service.UserService;
    import util.MySpring;
    import util.ThreadLocalManager;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class LoginController extends HttpServlet {
    
        private UserService service = MySpring.getBean("service.UserService");
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //处理字符集
            request.setCharacterEncoding("UTF-8");
            //获取请求发过来的参数
            String uname = request.getParameter("uname");
            String upassword = request.getParameter("upassword");
            //如果service不改变结构
            String result = service.login(uname,upassword);
            //根据结果转发
            if(result.equals("登录成功")){
                //获取service中的那个domain对象
                //对象.get("user");
                ThreadLocal local = ThreadLocalManager.getThreadLocal(uname);
                User user = (User)local.get();   // 将user从ThreadLocal对象的ThreadLocalMap中取出
                request.setAttribute("user",user);  //然后再将user存入request域中,方便页面的取值
                request.getRequestDispatcher("welcome.jsp").forward(request,response);
            }else{
                request.getRequestDispatcher("index.jsp").forward(request,response);
            }
    
    
    
    
            //调用业务层方法做事---原有的
    //        String result = service.login(uname,upassword);
    //        //根据结果给予响应(通常转发)
    //        if(result.equals("登录成功")){
    //            //需要将昵称带走   交给welcome进行拼接--展示
    //            String nickName = service.getNickName(uname);
    //            request.setAttribute("nickName",nickName);
    //
    //        }else{
    //            request.getRequestDispatcher("index.jsp").forward(request,response);
    //        }
    
    
            //如果按照方案二修改原有的service登录方法   返回值类型与平时习惯不一样
    //        User user = service.login(uname,upassword);
    //        if(user!=null){
    //            request.setAttribute("nickName",user.getNickname());
    //            request.getRequestDispatcher("welcome.jsp").forward(request,response);
    //        }else{
    //            request.getRequestDispatcher("index.jsp").forward(request,response);
    //        }
        }
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req,resp);
        }
    }
    

    UserService

    package service;
    
    import dao.UserDao;
    import domain.User;
    import util.MySpring;
    import util.ThreadLocalManager;
    
    public class UserService {
    
        private UserDao dao = MySpring.getBean("dao.UserDao");
    
        //方案一   再设计一个方法 获取昵称    性能问题
    //    public String getNickName(String uname){
    //        String nickName = dao.selectOne(uname).getNickname();
    //        System.out.println(nickName);
    //        return nickName;
    //    }
    
    
        //方法负责登录
    
    //    public User login(String uname,String upassword){
    //        User user = dao.selectOne(uname);//user对象 包含所有信息 name pass nick
    ////        if(user!=null && user.getUpassword().equals(upassword)){
    ////            return "登录成功";
    ////        }
    ////        return "用户名或密码错误";
    //
    //        //方案二   修改原有的登录方法
    //        //方案二 将user对象整体返回   返回值类型与之前一个登录结果看似不同  不习惯
    //        if(user!=null && user.getUpassword().equals(upassword)){
    //            return user;
    //        }
    //        return user;
    //    }
    
        //方案三  不改变原有登录方法结构的情况下  将domain对象带走
        //想要将结果带走 通常是返回值
        //想到了session的特点     某一个地方存储信息   隔着的地方取
        public String login(String uname,String upassword){
            User user = dao.selectOne(uname);
            //将domain对象拆开 做业务逻辑判断
            if(user!=null && user.getUpassword().equals(upassword)){
                // 对象.set("user",user);
                ThreadLocal local = ThreadLocalManager.getThreadLocal(uname);
                local.set(user);// local value      将user放入ThreadLocal对象的ThreadLocalMap中
                return "登录成功";
            }
            return "用户名或密码错误";
        }
    }
    
    

    UserDao

    package dao;
    
    import domain.User;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    public class UserDao {
    
        //查询单条记录
        public User selectOne(String uname){
            User resultUser = null;
            try {
                //JDBC
                String driver = "com.mysql.jdbc.Driver";
                String url = "jdbc:mysql://localhost:3306/shopping?useSSL=true";
                String user = "root";
                String password = "root";
                String sql = "SELECT UNAME,UPASSWORD,NICKNAME FROM USER WHERE UNAME = ?";
                Class.forName(driver);
                Connection conn = DriverManager.getConnection(url,user,password);
                PreparedStatement pstat = conn.prepareStatement(sql);
                pstat.setString(1,uname);
                ResultSet rs = pstat.executeQuery();
                if(rs.next()){
                    resultUser = new User();
                    resultUser.setUname(rs.getString("uname"));
                    resultUser.setUpassword(rs.getString("upassword"));
                    resultUser.setNickname(rs.getString("nickname"));
                }
                rs.close();
                pstat.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return resultUser;
        }
    }
    
    

    ThreadLocal的set方法源码

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);     // 获取线程t中的ThreadLocalMap
        if (map != null)
            map.set(this, value);   // 见代码1
        else
            createMap(t, value);    // 创建新的ThreadLocalMap
    }
    

    welcome.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
        <body>
            欢迎${requestScope.user.nickname}进入系统<br>
        </body>
    </html>
    

    相关文章

      网友评论

          本文标题:ThreadLocal

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