JavaWeb入门到入土_Day04

10. MVC三层架构

MVC:Model View Controller 模型视图控制器

10.1 早期

早期web架构
用户直接访问控制层,控制层就可以直接操作数据库;

Servlet(CRUD)——>数据库
弊端:程序异常拥堵,不利于维护;
Servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码;

在架构中,没有什么是加一层解决不了的!
数据库:程序员——JDBC——MySQL、Oracle、SQLSever...

10.2 MVC三层架构

改进后的web架构
View

  • 展示数据
  • 提供链接发起Servlet请求

Controller(Servlet)

  • 接收用户的请求(req:请求参数、Session信息…)
  • 交给业务层处理对应的代码
  • 控制视图的跳转

Model

  • 业务处理:业务逻辑(Service)
  • 数据持久层:CRUD(Dao)
     登录  
---> 接收用户的登录请求  
---> 处理用户的请求(获取用户登录的参数,username,password)
---> 交给业务处理登录业务(判断用户名密码是否正确:事务)
---> Dao层查询用户名和密码是否正确
---> 数据库

11. Filter(过滤器)(重点)

  Filter可以通过拦截web服务器管理的web资源(JSP、Servlet、静态图片文件或静态 html 文件)来实现一些特殊的功能,例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
  它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
过滤器作用
开发步骤:

  • 导包
  • 编写过滤器
    • 注意导包问题;
    import javax.servlet.Filter;
    
    • 实现Filter接口,重写对应的方法即;
    • web.xml中配置过滤器
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.wang.servlets.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/servlet/hello</url-pattern>
    </servlet-mapping>
    
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>com.wang.filters.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
    

HelloServlet.java

package com.wang.servlets;

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 HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("你好,世界!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

CharacterEncodingFilter.java

package com.wang.filters;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {
    
    // 初始化:web服务器启动的时候,初始化就会执行
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CharacterEncodingFilter 初始化...");
    }

    /**
     * chain:链
     * 1.过滤器中的代码,在过滤特定请求的时候会执行
     * 2.必须让过滤器继续通行
     *   chain.doFilter(request, response);
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
		response.setContextType("text/html;charset=UTF-8");

        System.out.println("doFilter执行前...");
        chain.doFilter(request, response);   // 让请求继续走,如果不写的话程序到这里就被拦截停止了!
        System.out.println("doFilter执行后...");
    }

    // 销毁:web服务器关闭的时候,过滤器会销毁
    public void destroy() {
        System.out.println("CharacterEncodingFilter 销毁...");
    }
}

12. Listener(监听器)

监听器的种类非常多,但整体上的功能是有相同之处的。

  1. 编写一个监听器,实现监听器的接口
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

// 统计网站在线人数,也即session数量
public class OnLineCountListener implements HttpSessionListener {
    // 创建session的监听,每次创建session都会触发这个事件
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println(se.getSession().getId());
        ServletContext servletContext = se.getSession().getServletContext();
        Integer onLineCount = (Integer) servletContext.getAttribute("onLineCount");
        if (onLineCount == null) {
            onLineCount = new Integer(1);
        } else {
            onLineCount = new Integer(onLineCount + 1);
        }
        servletContext.setAttribute("onLineCount", onLineCount);
    }

    // 销毁session的监听,一旦销毁session就会触发这个事件
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext servletContext = se.getSession().getServletContext();
        Integer onLineCount = (Integer) servletContext.getAttribute("onLineCount");
        if (onLineCount == null) {
            onLineCount = new Integer(0);
        } else {
            onLineCount = new Integer(onLineCount - 1);
        }
        servletContext.setAttribute("onLineCount", onLineCount);
        se.getSession().invalidate();   // 手动销毁session
    }

    /**
     * session的销毁
     * 1.手动销毁  getSession().invalidate();
     * 2.自动销毁
     * <session-config>
     *     <session-timeout>1</session-timeout>
     * </session-config>
     * 3.关闭服务器
     */
}
  1. 注册监听器web.xml
<!--注册监听器-->
<listener>
    <listener-class>com.wang.listeners.OnLineCountListener</listener-class>
</listener>
  1. 页面验证
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <h1>当前共有<span><%=this.getServletConfig().getServletContext().getAttribute("onLineCount")%></span>人访问</h1>
  </body>
</html>

测试界面

13. 过滤器、监听器常见应用

13.1 GUI中监听器的理解及应用

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestPanel {
    public static void main(String[] args) {
        Frame frame = new Frame("测试");   // 新建一个窗体
        Panel panel = new Panel();   // 新建一个面板

        frame.setLayout(null);   // 设置窗体的布局
        frame.setBounds(300, 300, 500, 500);
        frame.setBackground(new Color(0, 0, 255));   // 设置背景颜色
        panel.setBounds(50, 50, 300, 300);
        panel.setBackground(new Color(255, 0, 0));   // 设置背景颜色

        frame.add(panel);   
        frame.setVisible(true);

        //添加一个窗口关闭的监听事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

13.2 Filter实现权限拦截

用户登录之后才能进入主页!用户注销后就不能进入主页了!

  • 用户登录后,在session中放入用户数据
  • 进入主页的时候要判断用户是否已经登录(要求:在过滤器中实现)

登录界面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>

<form method="post" action="/servlet/login">
    <input type="text" name="username">
    <input type="submit">
</form>

</body>
</html>

失败界面 error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>失败</title>
</head>
<body>

<h1>失败</h1>
<h3>没有权限,用户输入有误</h3>

<p><a href="login.jsp">返回登录页面</a></p>

</body>
</html>

登录接口 LoginServlet

import com.wang.utils.Constant;

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 LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("username");
        if (username.equals("admin")) {   // 登录成功
            req.getSession().setAttribute(Constant.USER_SESSION, req.getSession().getId());
            // 重定向至成功界面
            resp.sendRedirect("/sys/success.jsp");
        } else {   // 登录失败,重定向至失败界面
            resp.sendRedirect("/error.jsp");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

注销接口 LogoutServlet

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 LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object userSession = req.getSession().getAttribute(Constant.USER_SESSION);
        if (userSession != null) {
            req.getSession().removeAttribute(Constant.USER_SESSION);
            // 跳转到登录页面
            resp.sendRedirect("/login.jsp");
        } else {
            // 跳转到登录页面
            resp.sendRedirect("/login.jsp");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

常量类 Constant

public class Constant {
    public static final String USER_SESSION = "USER_SESSION";
}

过滤器 LoginFilter

import com.wang.utils.Constant;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse rep = (HttpServletResponse) response;
        Object userSession = req.getSession().getAttribute(Constant.USER_SESSION);
        if (userSession == null) {
            //跳转错误页面
            rep.sendRedirect("/error.jsp");
        }
        chain.doFilter(request, response);
    }

    public void destroy() {}
}

接口配置 web.xml

    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.wang.servlets.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/servlet/login</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>logout</servlet-name>
        <servlet-class>com.wang.servlets.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>logout</servlet-name>
        <url-pattern>/servlet/logout</url-pattern>
    </servlet-mapping>

	<!--注册过滤器-->
    <filter>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.wang.filters.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/sys/*</url-pattern>
    </filter-mapping>

14. JDBC

14.1 What

JDBC(Java Database Connectivity):Java数据库连接
JDBC
连接数据库需要的jar包:

  • java.sql
  • javax.sql
  • mysql-connection-java(连接驱动)

14.2 应用实例

实验环境搭建

DROP TABLE `users`;

CREATE TABLE `users`(
  `id` INT PRIMARY KEY,
  `name` VARCHAR(50) NOT NULL,
  `password` VARCHAR(40) NOT NULL,
  `email` VARCHAR(60) NOT NULL,
  `birthday` DATE
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('1','张三','123456','zhangsan@sina.com','2021-07-14');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('2','李四','123456','lisi@sina.com','1981-12-04');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('3','王五','123456','wangwu@sina.com','1982-12-04');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('4','赵六','123456','zhaoliu@sina.com','1987-12-05');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('5','钱七','123456','qianqi@sina.com','2021-07-19');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('6','刘八','123456','liuba@sina.com','2021-07-19');

导入数据库依赖pom.xml

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>
</dependencies>

JDBC固定步骤:

  1. 加载驱动;
  2. 连接数据库,Connection实例化对象代表数据库;
  3. 实例化向数据库发送SQL语句的Statement、PreparedStatement(安全):CRUD;
  4. 根据业务编写不同的SQL语句;
  5. 执行SQL;
  6. 关闭连接
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJdbc {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        try {

            //1. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2. 连接数据库
            Connection con = DriverManager.getConnection(url, user, pwd);
            //3. 向数据库发送sql的对象Statement
            Statement statement = con.createStatement();

            //4. sql
            String str = "select * from users";

            //5. 执行sql
            ResultSet rs = statement.executeQuery(str);
            while (rs.next()) {
                System.out.println("id=" + rs.getInt("id"));
                System.out.println("name=" + rs.getString("name"));
                System.out.println("password=" + rs.getString("password"));
                System.out.println("email=" + rs.getString("email"));
                System.out.println("birthday=" + rs.getString("birthday"));
            }
            //6. 关闭
            rs.close();
            statement.close();
            con.close();

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

预编译

public class TestJdbc {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        try {

            // 1. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2. 连接数据库
            Connection con = DriverManager.getConnection(url, user, pwd);

            // 3. sql语句
            String str = "insert into users(id, name, password, email, birthday) values (?,?,?,?,?)";
            // 4. 预编译
            PreparedStatement statement = con.prepareStatement(str);
            statement.setInt(1,7);
            statement.setString(2,"小王");
            statement.setString(3,"123456");
            statement.setString(4,"xiaowang@sina.com");
            statement.setDate(5,new java.sql.Date(System.currentTimeMillis()));

            // 5.执行sql
            int count = statement.executeUpdate();

            if (count > 0) {
                System.out.println("插入成功!");
            }
            statement.close();
            con.close();

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

14.3 事务

特点:要么都成功,要么都失败!
ACID原则:保证数据的安全性

开启事务
事务提交  commit()
事务回滚  rollback()
关闭事务

单元测试Junit

单元测试依赖

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.13</version>
</dependency>

@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!

import org.junit.Test;

public class TestJdbc {
    @Test
    public void test() {
        System.out.println("hello");
    }
}

搭建环境测试

创建表

CREATE TABLE `account`(
  `id` INT PRIMARY KEY,
  `name` VARCHAR(50) NOT NULL,
  `money` FLOAT NOT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `account` (`id`, `name`, `money`) VALUES(1,'A',1000);
INSERT INTO `account` (`id`, `name`, `money`) VALUES(2,'B',1000);
INSERT INTO `account` (`id`, `name`, `money`) VALUES(3,'C',1000);

命令行命令

# 开启事务
start transaction ;

# 模拟转账
update account set money = money - 100 where name = 'A';
update account set money = money + 100 where name = 'B';

# 回滚
rollback ;

# 提交
commit;

测试

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Test3Jdbc {
    @Test
    public void test() {
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        Connection con = null;
        try {

            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection(url, user, pwd);

            // 开启事务 这里不开启事务的话异常情况就会有问题,false是开启
            con.setAutoCommit(false);

            con.prepareStatement("update account set money=money-100 where name='A'").executeUpdate();
            // 制造错误
			// int i = 1 / 0;
            con.prepareStatement("update account set money=money+100 where name='B'").executeUpdate();

            con.commit();
            System.out.println("success");
        } catch (Exception e) {
            System.out.println("error rollback");
            if (con != null) {
                try {
                    con.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值