Day56.Servlet: Request、Response、书城二阶段

Day56.Servlet: Request、Response、书城二阶段,第1张

目录

一、请求 Request

Request 获取请求参数(重要)

BeanUtils工具类

Request 请求转发(服务器内部转发) 

请求域对象

二、响应 Response

向客户端响应一个文件 (getOutputStream)

重新定向 (sendRedirect)

三、项目:书城二阶段: 登录注册功能_数据库链接

一、使用base标签统一页面基础访问路径

二、编写实体类、数据库中创建表单

三、表述层 (Servlet),修改html表单地址,封装bean对象

四、数据访问层(DAO)  (暂时使用JDBC)

五、业务层 (Service)、密码MD5处理

六、补充:相关工具类


一、请求 Request

Request就是服务器中的一个对象,该对象中封装了HTTP请求的请求行、请求头和请求体的内容。

Request获取HTTP请求的内容:

1.请求行、请求头

public class ServletRequest1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求行信息
        //获取请求方式
        String method = request.getMethod();
        System.out.println("method = " + method);
        //获取URL 统一资源定位符 
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("requestURL = " + requestURL);
        //获取URI 统一资源标识符
        String requestURI = request.getRequestURI();
        System.out.println("requestURI = " + requestURI);
        //获取协议
        String protocol = request.getProtocol();
        System.out.println("protocol = " + protocol);

        //获取请求头信息
        //获取客户端信息
        String agent = request.getHeader("User-Agent");
        System.out.println("agent = " + agent);
        //获取引用页(上一页)
        String referer = request.getHeader("Referer");
        System.out.println("referer = " + referer);
    }
}


获取请求行、头信息

Request 获取请求参数(重要)

方法名

返回值类型

方法描述

request.getParameter("请求参数的名字")

String

根据一个参数名获取一个参数值

request.getParameterValues("请求参数的名字")

String []

根据一个参数名获取多个参数值

request.getParameterNames()

Enumeration

获取当前请求的所有参数的参数名

request.getParameterMap()

Map

获取当前请求的所有参数,以键值对的方式存储到Map中

request.setCharacterEncoding("utf-8");

Post会中文乱码,需要设置编码解决

public class ServletRequest2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.根据一个参数名获取一个参数值
        System.out.println("---------- getParameter() ----------");
        String uname = request.getParameter("uname");
        String pwd = request.getParameter("pwd");
        System.out.println(uname + "->" +pwd);

        //2.根据一个参数名获取多个参数值
        System.out.println("---------- getParameterValues() ----------");
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("hobby->"+ Arrays.toString(hobbies));

        //3.获取当前请求的所有参数,以键值对的方式存储到Map中
        System.out.println("---------- parameterMap() ----------");
        Map parameterMap = request.getParameterMap();
        parameterMap.forEach(new BiConsumer() {
            @Override
            public void accept(String s, String[] strings) {
                System.out.println(s+"->"+Arrays.toString(strings));
            }
        });
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Post会中文乱码,需要设置编码解决(因为系统默认utf编码)
        request.setCharacterEncoding("utf-8");

        //1.根据一个参数名获取一个参数值
        System.out.println("---------- getParameter() ----------");
        String uname = request.getParameter("uname");
        String pwd = request.getParameter("pwd");
        System.out.println(uname + "->" +pwd);
    }
}

get的方式
用户名:
密码:
爱好: 游泳 读书 跑步

post的方式
用户名:
密码:
爱好: 游泳 读书 跑步

 

BeanUtils工具类

Apache 下的软件包,其主要目的是利用反射机制对 JavaBean 的属性进行处理。(此处只是用来将表单数据快速封装为对象)

//调用getParameterMap() 获取当前请求内表单中的所有参数,
Map userMap = request.getParameterMap();

//准备一个User对象
User user = new User();

//进行封装,完成
BeanUtils.populate(user,userMap);

不使用工具封装对象:

        //获取所有参数
        Map userMap = request.getParameterMap();
        String uname = userMap.get("uname")[0]; //获取name

        String age = userMap.get("age")[0];     //获取age

        String gender = userMap.get("gender")[0];  //获取gender

        User user = new User(uname,age,gender);

Request 请求转发(服务器内部转发) 

请求转发:从一个资源跳转到另一个资源,浏览器只会发起一次请求,连接不会发生改变

请求转发可以跳转到WEB-INF中的资源

请求转发的API:

request.getRequestDispatcher("路径").forward(request,response);

代码: 

public class ServletDispatcher1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Dispatcher1 duGet() ------");
        String uname = request.getParameter("uname");
        System.out.println("uname = " + uname);

        //将请求传递到 Dispatcher2
        request.getRequestDispatcher("/dispatcher2").forward(request,response);
    }
}
public class ServletDispatcher2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Dispatcher2 duGet() ------");
        //同一个链接,可以获取当前链接资源
        String uname = request.getParameter("uname");
        System.out.println("Dispatcher2 uname = " + uname);

        //请求转发访问WEB-INF内的资源
        request.getRequestDispatcher("/WEB-INF/dispatcher.html").forward(request,response);
    }
}
regist.html
请求转发
用户名:
web.xml
    
        ServletDispatcher1
        /dispatcher1
    

    
        ServletDispatcher2
        /dispatcher2
    

WEB-INF内资源

 成功访问WEB—INF资源 

  

请求域对象

全局域是整个项目范围的所有动态资源都能够共享的一个范围;而请求域的范围只是在一次请求中的动态资源能够共享的一个范围。

  • 往请求域中存入数据:request.setAttribute(key,value)

  • 从请求域中取出数据:request.getAttribute(key)

  • (全局域对象是通过ServletContext.serAttribute设置)

请求域对象一定要和请求转发一起使用,因为请求域的范围是一次请求范围内,所以要在两个动态资源中使用请求域必须要进行请求转发跳转。

二、响应 Response

Response也是服务器端一个对象,它里面可以封装要响应给客户端的响应行、头、体的信息。

向客户端反馈信息、解决乱码问题:

setContentType("text/html;charset=utf-8");

该方法同时让服务器和客户端都使用UTF-8,还设置了响应头。

一定要在获取流对象之前调用

public class ServletResponse1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //向用户反馈数据,解决响应乱码问题
        response.setContentType("text/html;charset=utf-8");
        //反馈信息
        response.getWriter().println("ServletResponse1成功!");
    }
}

 请求和响应:

向客户端响应一个文件 (getOutputStream)

ServletOutputStream os = response.getOutputStream();

public class ServletResponse2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.先通过Context获取文件真实路径
        ServletContext s1 = getServletContext();
        String realPath = s1.getRealPath("img/200F6093053-7.jpg");
        //2.创建输入流,读取图片
        FileInputStream fis = new FileInputStream(realPath);
        //3.通过Response获取输出流
        ServletOutputStream os = response.getOutputStream();
        //4.边读边写
        int length =0;
        while ((length=fis.read())!=-1){
            os.write(length);
        }
        //5.关闭流

        //可以使用codota插件 或 IOUtils工具 快捷完成
        //IOUtils.copy(fis,os);
    }
}
重新定向 (sendRedirect)

重定向是由项目中的一个资源跳转到另一个资源,在这个过程中客户端会发起新的请求。

  1. 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求

  2. 重定向跳转可以跳转到任意服务器的资源,但是无法访问WEB-INF中的资源

  3. 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径

重定向的API:

response.sendRedirect("路径");

代码: 

public class ServletResponse3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取上下文路径
        String contextPath = request.getContextPath();

        //重定向 此时/代表服务器根目录,响应状态码302
        response.sendRedirect(contextPath+"/response2");
    }
}

请求转发和重定向的区别:

  1. 重定向会由浏览器发起新的请求,而请求转发不会发起新的请求

  2. 重定向可以访问任意互联网资源,而请求转发只能访问本项目资源

  3. 重定向不能访问本项目的WEB-INF内的资源,而请求转发可以访问本项目的WEB-INF内的资源

  4. 发起重定向的资源和跳转到的目标资源没在同一次请求中,所以重定向不能在请求域中使用;而发起请求转发的资源和跳转到的目标资源在同一次请求中,所以请求转发可以在请求域中使用

三、项目:书城二阶段: 登录注册功能_数据库链接

注意:jar包,lib文件夹放在 WEB-INF下!

一、使用base标签统一页面基础访问路径
  • base标签要写在head标签内,写在所有其他有路径的标签的前面。

  • base标签生效的机制是:最终的访问地址=base标签href属性设置的基准+具体标签内的路径

  • 如果某个路径想要基于base中的路径进行路径编写,那么它不能以/开头

部分举例:


  
    
    
    
    
    
    新日暮里会员登录页面       
    
    
  

 Ctrl + R快速替换

二、编写实体类、数据库中创建表单

注意:html标签name值 需要与 实体类属性相同

public class User {
    //pojo 和 bean 都表示实体类
    private Integer uid;
    private String uname;
    private String upwd;
    private String email;
    ...略
}
CREATE TABLE t_user(
	uid INT PRIMARY KEY auto_increment,
	uname VARCHAR(50),
	upwd VARCHAR(20),
	email VARCHAR(20)
);
三、表述层 (Servlet),修改html表单地址,封装bean对象

注意:此时的业务层对象是在最后一步完成编写。

注册:

注册:
public class Regist extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Regist ------");
        //1.解决请求,响应乱码问题
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=UTF-8");

        //2.获取表单参数,封装为对象
        Map Map = request.getParameterMap();

        try {
            //3.工具类封装为对象 BeanUtils.populate(user(对象),userMap(参数集合));
            User user = new User();
            BeanUtils.populate(user, Map);

            //4.调用业务层 判断是否可以添加
            UserService userService = new UserServiceImpl();

            //添加数据,没有发生异常注册成功
            userService.registUser(user);
            response.sendRedirect(request.getContextPath()+"/pages/user/regist_success.html");

        } catch (Exception e) {
            e.printStackTrace();
            //4.2 发生异常则注册失败
            response.getWriter().println("用户名已存在,注册失败。");
        }
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

登录:

登录:
public class Login extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("------ Login ------");
        //1.解决请求,响应乱码问题
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=UTF-8");

        //2.获取表单参数
        Map map = request.getParameterMap();
        
        try {
            //3.调用工具类封装为对象
            User user = new User();
            BeanUtils.populate(user,map);

            //4.创建业务层对象,完成登录
            UserServiceImpl userService = new UserServiceImpl();

            User login = userService.login(user);
            //登陆成功
            response.sendRedirect(request.getContextPath()+"/pages/user/login_success.html");

        } catch (Exception e) {
            //登陆失败
            e.printStackTrace();
            response.getWriter().println("登录失败,请检查您的用户名或密码");
        }
    }
}
四、数据访问层(DAO)  (暂时使用JDBC)

 代码:和下面差不多

Day50.JDBC — 数据库连接池、DBUtils工具类、封装DOA层代码、ThreadLocal_焰火青年·的博客-CSDN博客​​​​​​

五、业务层 (Service)、密码MD5处理
//用户业务层
public interface UserService {
    //注册业务
    void registUser(User user);
    //登录业务
    User login(User user);
}

注册:

//业务层实现类
public class UserServiceImpl implements UserService {
    //创建用户数据访问层对象
    UserDaoImpl userDao = new UserDaoImpl();
    //注册的方法
    @Override
    public void registUser(User user) {
        //1.获取用户名
        String uname = user.getUname();

        //2.判断用户名是否已经存在
        User user1 = userDao.selectByName(uname);

        if(user1==null){
            //3.1 不存在,对密码加密 *** 作,存入数据
            String encode = MD5Util.encode(user.getUpwd());
            user.setUpwd(encode);
            //通过数据访问层添加到数据库
            userDao.insertUser(user);
        } else {
            //3.2 如果存在,无法存储
            throw new RuntimeException("用户"+uname+"已存在,无法添加");
        }
    }

登录:

    //登录的方法
    @Override
    public User login(User user) {
        //1.根据用户名查询是否存在此用户
        User u = userDao.selectByName(user.getUname());

        //2.判断用户名是否存在
        if(u!=null){
            //3.密码是否一致(先将密码转为MD5)
            String encode = MD5Util.encode(user.getUpwd());
            if(encode.equals(u.getUpwd())){
                //4.1 密码相同返回 User
                return u;
            }else {
                //4.2 密码不同抛出异常
                throw new RuntimeException("密码错误");
            }
        } else {
            //2,2用户名不存在,抛出异常
            throw new RuntimeException("用户名不存在");
        }
    }
}

最后补充表述层代码,测试,完成。

六、补充:相关工具类

MD5Util

public class MD5Util {
    /**
     * 针对明文字符串执行MD5加密
     * @param source
     * @return
     */
    public static String encode(String source) {

        // 1.判断明文字符串是否有效
        if (source == null || "".equals(source)) {
            throw new RuntimeException("用于加密的明文不可为空");
        }

        // 2.声明算法名称
        String algorithm = "md5";

        // 3.获取MessageDigest对象
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 4.获取明文字符串对应的字节数组
        byte[] input = source.getBytes();

        // 5.执行加密
        byte[] output = messageDigest.digest(input);

        // 6.创建BigInteger对象
        int signum = 1;
        BigInteger bigInteger = new BigInteger(signum, output);

        // 7.按照16进制将bigInteger的值转换为字符串
        int radix = 16;
        String encoded = bigInteger.toString(radix).toUpperCase();

        return encoded;
    }
}

JDBCUtils (Druid数据库连接池)

public class JDBCUtils {
    static DataSource dataSource;
    //ThreadLocal,每个线程独有,用于存储共享变量
    static ThreadLocal local = new ThreadLocal<>();

    //静态代码块
    static {
        //属性集对象
        Properties pro = new Properties();
        try {
            //将配置文件信息 读取到属性集内  (将配置文件信息转为 字节流)
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
            //通过配置文件创建了链接对象
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //通过连接池获取链接
    public static Connection getConnection() throws SQLException {

        Connection connection = local.get();
        //如果ThreadLocalMap内不存在,用连接池获取,存在则直接返回
        if(connection==null){
            //连接池获取
            connection = dataSource.getConnection();
            //放入ThreadLocal内
            local.set(connection);
        }
        return connection;
    }
    //关闭链接方法
    public static void closeConnectiopn() throws Exception{
        Connection connection = JDBCUtils.getConnection();
        //事务关闭,防止后面复用出现问题
        connection.setAutoCommit(true);
        //删除线程内存储的链接
        local.remove();

        connection.close();
    }
}

BaseDao (通用CURD)

public class BaseDaoImpl {
    //通用的BaseDao 通用的增 删 改 查方法
    public void update(String sql,Object...params) {
        try {
            //1.获取链接
            Connection connection = JDBCUtils.getConnection();
            //2.创建queryRunner
            QueryRunner queryRunner = new QueryRunner();

            //3.执行 *** 作
            queryRunner.update(connection,sql,params);

        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 通用的查询多条数据
     * @param clazz  集合的泛型类型
     * @param sql
     * @param params 参数
     * @param 
     * @return
     */
    //不确定查询哪张表,加入泛型!!!!
    public  List findAll(Class clazz, String sql, Object... params) {
        try {
            //1.获取链接
            Connection connection = JDBCUtils.getConnection();
            //2.创建queryRunner
            QueryRunner queryRunner = new QueryRunner();

            List query = queryRunner.query(connection, sql, new BeanListHandler<>(clazz), params);

            return query;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * 通用的返回单个对象
     * @param clazz   bean的链接类型
     * @param sql
     * @param params  参数
     * @param 
     * @return
     */
    public  T findOneBean(Class clazz, String sql, Object... params) {
        try {
            //1.获取链接
            Connection connection = JDBCUtils.getConnection();
            //2.创建queryRunner
            QueryRunner queryRunner = new QueryRunner();

            T bean = queryRunner.query(connection, sql, new BeanHandler<>(clazz), params);

            return bean;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * 通用的查询单个值,暂未用到
     * @param sql
     * @param params
     * @return
     */
    public Object getSingleValue(String sql,Object...params){
        try {
            //1.获取链接
            Connection connection = JDBCUtils.getConnection();
            //2.创建queryRunner
            QueryRunner queryRunner = new QueryRunner();

            Object query = queryRunner.query(connection, sql, new ScalarHandler<>(), params);

            return query;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/872182.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存