java入门-javaWeb(三)

MVC三层架构
三层架构也就是:实体层,视图层,控制层
实体层Model:包括业务service层,crud操作数据库的dao层,实体类pojo/entity,以及jdbc跟数据库进行连接。
视图层view:包括jsp,html,vue等界面,展示数据模型,供用户操作。
控制层controller:接收用户请求,响应用户请求,视图跳转(转发和重定向)。
在这里插入图片描述
Filter(过滤器)
过滤器的应用:对请求或响应信息进行过滤的的通用方法
1.解决汉字乱码问题
2.登陆验证
使用过滤器的步骤:
1.导入jar包

<dependencies>
        <!--servlet依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <!--jsp依赖-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
        </dependency>
        <!--jstl表达式依赖-->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl-api</artifactId>
            <version>1.2</version>
        </dependency>
        <!--standard标签库依赖-->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!--数据库连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

2.实现javax.servlet的Filter,重写初始化,执行过滤内容,销毁的方法
初始化方法:服务器启动时,执行初始化方法,即过滤器启动
执行过滤内容:filterChain.doFilter是过滤器的关键,如果没有这句话,执行代码会停留在Filter内,不会进入servlet内。
销毁:服务器关闭后,执行Filter销毁的方法。

public class ChracterEncodingFilter implements Filter {
        //ChracterEncodingFilter初始化,tomcat服务器启动,Filter就初始化了
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("character初始化");
        }
        //filterChain过滤器链
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            servletRequest.setCharacterEncoding("utf-8");
            servletResponse.setCharacterEncoding("utf-8");
            servletResponse.setContentType("text/html;charset=utf-8");
            //filterChain.doFilter是为了将servletRequest,servletResponse传递下去,没有这个,执行代码会停留在过滤器内,无法进入servlet
            System.out.println("character传递前");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("character传递后");
        }
        //CharacterEncodingFilter销毁,tomcat服务器关闭,过滤器才会销毁
        public void destroy() {
            System.out.println("character销毁");
        }
}

3.配置web.xml
如果servlet的的前缀和Filter过滤器的的前缀相同,则该地址下的servlet在执行前,会先执行Filter内容。

<filter>
        <filter-name>adminFilter</filter-name>
        <filter-class>com.wp.filter.AdminFilter</filter-class>
    </filter>
    <filter>
        <filter-name>chracterEncodingFilter</filter-name>
        <filter-class>com.wp.filter.ChracterEncodingFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>adminFilter</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>chracterEncodingFilter</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>showServlet</servlet-name>
        <servlet-class>com.wp.servlet.ShowServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>servletDemo01</servlet-name>
        <servlet-class>com.wp.servlet.ServletDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>showServlet</servlet-name>
        <url-pattern>/servlet/show</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>servletDemo01</servlet-name>
        <url-pattern>/servlet/demo01</url-pattern>
    </servlet-mapping>

filter实现权限拦截:存在登陆页面和登陆成功的界面,还有一个登陆失败错误界面。达到的效果,登陆成功,进入主界面;点击主界面的注销,进入登陆界面,在未成功登陆的情况下,直接进入主界面,无法进入,会进入错误界面。
添加登陆界面,错误界面,系统主界面
在这里插入图片描述
登陆界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/servlet/login" method="post">
    <input type="text" name="username">
    <input type="submit">
</form>
</body>
</html>

登陆成功主界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--<%
    Object user_session = request.getSession().getAttribute("USER_SESSION");
    if(user_session==null){
        response.sendRedirect("/login.jsp");
    }
%>--%>
<h1>主页</h1>
<h3>登陆成功</h3>
<a href="/servlet/loginout">注销</a>
<a href="user.jsp" name="">user权限界面</a>
<a href="user.jsp">user权限界面</a>
</body>
</html>

登陆失败错误界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登陆错误</h1>
<a href="login.jsp">返回登陆页面</a>
</body>
</html>

登陆servlet代码:

String username = req.getParameter("username");
        if (username.equals("admin")){
            resp.sendRedirect("/sys/main.jsp");
            req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId());
        }
        else{
            resp.sendRedirect("/error.jsp");
        }

注销servlet代码:

req.getSession().removeAttribute(Constant.USER_SESSION);
resp.sendRedirect("/login.jsp");

过滤器代码:

System.out.println("进入admin.doFilter");
        HttpServletRequest servletRequest1 = (HttpServletRequest) servletRequest;
        HttpServletResponse servletResponse1 = (HttpServletResponse) servletResponse;
        if(servletRequest1.getSession().getAttribute(Constant.USER_SESSION)==null){
            servletResponse1.sendRedirect("/login.jsp");
        }
        /*String name = (String) servletRequest.getAttribute("name");
        if (name.equals("wp")){
            filterChain.doFilter(servletRequest,servletResponse);
        }*/
        filterChain.doFilter(servletRequest,servletResponse);

web.xml配置文件:

<filter>
        <filter-name>adminFilter</filter-name>
        <filter-class>com.wp.filter.AdminFilter</filter-class>
    </filter>
    <filter>
        <filter-name>chracterEncodingFilter</filter-name>
        <filter-class>com.wp.filter.ChracterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>adminFilter</filter-name>
        <url-pattern>/sys/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>chracterEncodingFilter</filter-name>
        <url-pattern>/servlet1/*</url-pattern>
    </filter-mapping>
    
    <servlet>
        <servlet-name>showServlet</servlet-name>
        <servlet-class>com.wp.servlet.ShowServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>servletDemo01</servlet-name>
        <servlet-class>com.wp.servlet.ServletDemo01</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.wp.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>loginoutServlet</servlet-name>
        <servlet-class>com.wp.servlet.LoginoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>showServlet</servlet-name>
        <url-pattern>/servlet/show</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>servletDemo01</servlet-name>
        <url-pattern>/servlet/demo01</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/servlet/login</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>loginoutServlet</servlet-name>
        <url-pattern>/servlet/loginout</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>com.wp.listener.OnlineCountListener</listener-class>
    </listener>
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>

可以将用户user实体类设置一个等级level的属性,用户登陆时,将用户信息存储到session中,然后在过滤器中,获取session中的用户等级信息,根据等级判断,是否有权限,有权限,就放行,无权限就返回信息。

Listener(监听器)
监听器的应用:监听各种触发事件,比如session的创建,session的销毁。
实现session监听,在启动服务器后,浏览器进行访问时,创建session;session销毁有两种方式,一种是手动销毁,一种自动销毁。
session手动销毁:

httpSessionEvent.getSession().invalidate();//手动销毁session

session自动销毁:在web.xml中配置,30分钟后销毁

<session-config>
        <session-timeout>30</session-timeout>
    </session-config>
//统计网站在线人数,一个用户对应一个session
public class OnlineCountListener implements HttpSessionListener {
    //创建session时触发此方法
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("进入session监听器");
        System.out.println(httpSessionEvent.getSession().getId());
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        Integer onlineCount = (Integer)(servletContext.getAttribute("onlineCount"));
        if (onlineCount==null){
            onlineCount=new Integer(1);
        }
        else{
            /*int count=onlineCount.intValue();
            onlineCount=new Integer(count+1);*/
            onlineCount+=1;
        }
        servletContext.setAttribute("onlineCount",onlineCount);
    }

    //销毁session时触发此方法
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("销毁session监听器");
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        Integer onlineCount = (Integer)(servletContext.getAttribute("onlineCount"));
        if (onlineCount==null){
            onlineCount=new Integer(0);
        }
        else{
           /* int count=onlineCount.intValue();
            onlineCount=new Integer(count-1);*/
            onlineCount-=1;
        }
        servletContext.setAttribute("onlineCount",onlineCount);
    }
}

注意:在启动服务器,浏览器访问后,可能会出现在线人数大于1,按道理应该只有一个在线,也就是一个session,这种情况是tomcat服务器的原因,启动浏览器时,tomcat去连接,就会创建session,有可能tomcat连接失败,这时tomcat会继续连接,知道连接成功,这样服务器自己创建了多个session,这时ReDeploy重新部署下程序,就可以解决这个问题。

监听器在GUI桌面中的应用:程序运行后,可以弹出一个桌面端程序

public class TestGUI {
    public static void main(String[] args) {
        Frame frame = new Frame("端午节快乐!");
        Panel panel=new Panel(null);
        frame.setLayout(null);

        frame.setBounds(300,300,500,500);
        frame.setBackground(new Color(0,0,255));

        panel.setBounds(50,50,400,400);
        panel.setBackground(new Color(0,255,0));

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

        //给窗口增加监听事件,一次性监听窗口的多个事件
        frame.addWindowListener(new WindowListener() {
            public void windowOpened(WindowEvent windowEvent) {
                System.out.println("窗口打开后");
            }

            public void windowClosing(WindowEvent windowEvent) {
                System.out.println("窗口关闭进行时");
                System.exit(0);//窗口正常关闭
                System.exit(1);//窗口异常关闭
            }

            public void windowClosed(WindowEvent windowEvent) {
                System.out.println("窗口关闭后");
            }

            public void windowIconified(WindowEvent windowEvent) {

            }

            public void windowDeiconified(WindowEvent windowEvent) {

            }

            public void windowActivated(WindowEvent windowEvent) {
                System.out.println("窗口激活,也就是在最顶层");
            }

            public void windowDeactivated(WindowEvent windowEvent) {
                System.out.println("窗口未激活,也就是不在最顶层");
            }
        });

//给窗口增加监听事件,选择性的给窗口增加监听事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("窗口关闭ing");
                System.exit(0);
            }
        });
    }
}

jdbc:java database connect
为了增加程序的迁移性,加一层统一驱动,然后使用各个数据库驱动。没有什么是加一层结构解决不了的。
在这里插入图片描述
第一步:导包
java.sql
javax.sql
mysql.connecter.java
最重要的是导mysql.connector.java包

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

使用池化技术dpcp.c3p0操作数据库优点,减少网络开销,提升数据库性能
使用dbcp池化技术,需导入包如下:

<!-- 数据库连接池commons-dbcp -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>

使用c3p0池化技术,需要导入的包如下:

<!-- 数据库连接池c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>mchange-commons-java</artifactId>
            <version>0.2.19</version>
        </dependency>

第二步:创建数据库表,配置dbcp的配置文件如下:

# 连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=Mysql@3306

# 初始化连接数
initialSize=10

# 最大连接数
maxActive=50

# 最大空闲连接数
maxIdle=20

# 最小空闲连接数
minIdle=5

# 超时等待时间,以毫秒为单位
maxWait=6000

#JDBC驱动建立连接时附带的连接属性
connectionProperties=useUnicode=true;characterEncoding=UTF8

# 自动提交
defaultAutoCommit=true

#连接池创建的连接为只读状态,注意没有设置值的情况下,则不会调用“setReadOnly”方法
defaultReadOnly=

#连接池创建的连接的事务级别 transactionIsolation的值范围:NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

C3P0的配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- c3p0的缺省(默认)配置,如果没有指定(ComboPooledDataSource的无参构造)则使用这个配置 -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/shop?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="password">Mysql@3306</property>

        <!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="acquireIncrement">5</property>
        <!-- 初始化数据库连接池时连接的数量 -->
        <property name="initialPoolSize">10</property>
        <!-- 数据库连接池中的最大的数据库连接数 -->
        <property name="maxPoolSize">20</property>
        <!-- 数据库连接池中的最小的数据库连接数 -->
        <property name="minPoolSize">5</property>
    </default-config>
    <!-- 命名的配置,ComboPooledDataSource的有参构造,且构造函数的参数为配置的配置的命名)可以通过方法调用实现 -->
    <named-config name="Mysql">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/shop?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="password">Mysql@3306</property>

        <!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="acquireIncrement">5</property>
        <!-- 初始化数据库连接池时连接的数量 -->
        <property name="initialPoolSize">10</property>
        <!-- 数据库连接池中的最大的数据库连接数 -->
        <property name="maxPoolSize">20</property>
        <!-- 数据库连接池中的最小的数据库连接数 -->
        <property name="minPoolSize">5</property>
    </named-config>
</c3p0-config>

将配置文件放到资源文件目录下

第三步:引用dbcp包资源,编写数据库连接工具类
dbcp数据库连接工具类:

package com.wp.util;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @author wp
 * @PackageName:com.wp.util
 * @ClassName:JdbcdbcpUtil
 * @Description:
 * @date:2021/6/25 15:49
 */
public class JdbcdbcpUtil {
    private static DataSource dt=null;
    static {
        try {
            InputStream inputStream= JdbcdbcpUtil.class.getClassLoader().getResourceAsStream("dpcp.properties");
            Properties properties=new Properties();
            properties.load(inputStream);
            dt= BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return dt.getConnection();
    }

    public static void release(Connection con, Statement st, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(con!=null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

c3p0数据库连接工具类:

package com.wp.util;

import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author wp
 * @PackageName:com.wp.util
 * @ClassName:JdbcUtil
 * @Description:
 * @date:2021/6/16 13:23
 */
public class Jdbcc3p0Util {
    private static DataSource dt=null;
    static {
        try {
            dt=new ComboPooledDataSource();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return dt.getConnection();
    }

    public static void release(Connection con, Statement st, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(con!=null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

第四步:测试操作数据库
dbcp:

public static void dpcbJdbcTest(){
        Connection con=null;
        PreparedStatement st=null;
        try {
            con= JdbcdbcpUtil.getConnection();
            //String sql="UPDATE ACCOUNT SET money=money-50 WHERE NAME='A'";
            String sql="UPDATE users SET password=123 WHERE NAME='曹操'";
            st=con.prepareStatement(sql);
            if(st.executeUpdate()>0){
                System.out.println("成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            JdbcdbcpUtil.release(con,st,null);
        }
    }

c3p0:

public static void c3p0JdbcTest(){
        Connection con=null;
        PreparedStatement st=null;
        try {
            con= Jdbcc3p0Util.getConnection();
            String sql="UPDATE ACCOUNT SET money=money-50 WHERE NAME='A'";
            //String sql="UPDATE users SET password=1 WHERE NAME='曹操'";
            st=con.prepareStatement(sql);
            if(st.executeUpdate()>0){
                System.out.println("成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            JdbcdbcpUtil.release(con,st,null);
        }
    }

注意:之前测试dbcp操作数据库时,通过调试,发现无法读取dbcp的配置文件,后来发现是因为配置文件路径问题,配置文件必须放在资源文件目录下。测试C3P0时,多次无法操作数据库,后来莫名其妙的又可以了。

数据库事务:要么都成功,要么都失败。
步骤:开启事务==>事务提交==>事务回滚==>关闭事务
在执行完数据库操作时,提交事务,在异常情况代码里,使用事务回滚,最后关闭事务。
典型例子:转账。
A向B转账100,正常逻辑A减少100,B增加100。为了避免意外情况下A账户减少100,但是B账户没有增加100,这时就要用到事务。
参考案例链接

事务案例代码:

 public void test() {
        Connection con= null;
        try {
            con = Jdbcc3p0Util.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //开启事务
        if (con != null) {
            try {
                con.setAutoCommit(false);
                String sqlA="update account set money=money-50 where name='A'";
                String sqlB="update account set money=money+50 where name='B'";
                PreparedStatement stA=con.prepareStatement(sqlA);
                PreparedStatement stB=con.prepareStatement(sqlB);
                if(stA.executeUpdate()>0 && stB.executeUpdate()>0){
                    System.out.println(1/0);
                    con.commit();
                }
                else{
                    con.rollback();
                }
            } catch (SQLException e) {
                try {
                    con.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            }
        }
        System.out.println("A");
    }

测试代码使用注解:目的是可以代替public static void main(string[] args)方法,直接可以测试,在pom文件里配置junit

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
@Test
    public void test2(){
        System.out.println("test2");
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值