JAVA入门基础_JAVAWEB

目录

1、前端知识的学习

HTML(Hyper Text Markup Language)超文本标记语言

常见标签

  • <html></html>

  • <head></head>

  • <meta charset="utf-8"/>(包裹在head标签中)

  • <body></body>

  • <footer></footer>

  • <hr/>

  • <br/>

  • <table></table><tr></tr><th></th><td></td>(不常用)

  • <frameset></frameset><frame></frame><iframe></iframe>

文字、段落标签

  • <h1></h1> ~ <h6></h6>

  • &ensp;&copy;&lt;&le;&gt;&le;&ge;

  • <p></p><span></span><u></u><i></i><b></b><sub></sub><sup></sup>

图片标签

<img src="图片地址" alt="当图片无法显示时显示" width="宽度" height="高度" title="鼠标悬浮显示的文字" />

列表标签

  • 有序列表<ol type="A|a|I|i|1" start="n 从几开始"> </ol>

    • <li></li>
    • <li></li>
  • 无序列表<ul type="dist|square|circle"> </ul>

    • <li></li>
    • <li></li>
  • 自定义列表<dl></dl>

    • <dt></dt>
    • <dd></dd>

表单

  • <form ation="需要提交到的地址" method="post|get(最大4kb,显示在地址栏)"></form>

    • <input type="输入框的类型" name="提交时的key" value="提交时的值"></input> 输入框
      • <input type="text"> 普通文本框
      • <input type="textarea"></input>" 多行文本框
      • <input type="password"> 密码框
      • <input type="radio" name="gender"> 单选框,根据name完成互斥
      • <input type="checkbox" name="hobby" checked>" 多选框,checked意思是默认选中
      • <input type="select"><option selected></option></input>" 下拉框
      • <input type="submit">" 提交按钮
      • <input type="reset">" 充值按钮
      • <input type="button">" 普通按钮
  • 提示:input标签中的一些属性解释

    • type:类型
    • name:相当于发送数据时的key
    • value :相当于发送数据时的value
    • checked:默认选中
    • selected:默认选择

a标签

  • <a></a>
    • href="链接地址"
    • target="_self|_blank|_parent|_top|framename"

Tomcat新建项目-部署-运行-访问

CS/BS架构的区别

  • CS:客户端服务器架构模式

    • 优点:可以将一部分安全要求不高的计算存储任务交由客户端进行,能够减轻服务器的压力以及网络负荷
    • 缺点:需要安装、维护成本高
  • BS:浏览器服务端架构模式

    • 优点:不需要安装,打开浏览器即可,维护成本低。
    • 缺点:服务端需要承载所有的压力,服务端的负载较重,并且由于所有的计算、存储任务都由服务端处理好了再返回给客户端,因此需要频繁的进行网络交互,网络负荷高

下载安装Tomcat、Tomcat的文件目录解析

  • 下载地址

  • 安装Tomcat,我这下载的是压缩版本,因此解压即可。注意:配置JAVA_HOME以及Tomcat解压目录不能有中文
    image

  • 由于Tomcat是用JAVA跟C语言写的,因此Tomcat运行过程中也需要JAVA的虚拟机来运行,因此需要配置JAVA_HOME
    image

创建一个最原始的JAVAWEB项目到webapps目录下

image
image

启动Tomcat并通过(context root)访问项目

context root:项目名称,一般为webapps目录下的根目录名,我这里是fristWebProject

  • 启动Tomcat,通过双击bin目录下的startup.bat文件
    image

使用IDEA工具完成WEB项目的创建、部署、运行

创建一个WEB项目

  • file -> new -> project
    image
  • 注意这个web包的颜色
    image

将一个普通项目修改为一个WEB项目

  • 假如我们创建了一个普通的JAVA项目,那么此时就只有一个src目录,并没有web项目,我们想要修改成一个web项目

  • File -> Project Structure -> Facts -> 点击+(加号) -> WEB

  • 修改Deployment Descriptors 下的Path目录,需要指定到web.xml文件
    image

  • 修改WEB Resource Directories下的Web Resource Directory的路径,需要指定到web目录
    image

导入一个WEB项目时,web目录没有变颜色时

  • 跟将一个普通项目修改为一个WEB项目的操作有点类似,不过第三步和第四步不再是修改,而是添加

部署WEB项目并运行

配置一个Tomcat模板,可以考虑添加自动更新类和资源

  • (1)点击页面中的Add Configuration,点击Templates下的TomcatServer下的Local
    image
    image

  • (2)在页面右侧配置Tomcat的路径,注意只保持到Tomcat安装路径即可

  • (3)看情况选择如下功能
    image

部署项目(添加artifact后添加全局lib)

  • (1)配置好了之后,再次点击Add Configuration,点击左侧的+(加号)添加一个Tomcat
    image

  • (2)配置一个artifact(解压后的web项目),此时也可以修改一下context root路径

  • (3)如果想要创建一个lib而让所有模块都可用的话,就在父级项目中创建一个lib放jar包

    • 其他的模块可以通过Project Structure -> Modules -> 选择需要导入jar包的项目 -> 选择Dependencies -> 添加一个Library

直接点击Run或者Debug运行

image
image

Idea使用Tomcat运行时需要注意的点以及项目的打包

  • IDEA在Tomcat项目运行时,会自动通过我们部署的Tomcat路径作为基础,复制一个新的Tomcat并将项目放在该新的Tomcat目录下运行。

  • Exploded的是创建解压后的war包,Archive的是war包(打包的时候用,添加一个Archive之后可以使用Idea的Build功能打包)
    image

Servlet 服务端程序(Server Applet)

创建一个最简单的Servlet

创建一个JAVA类,继承HttpServlet

image

配置web.xml文件

image

设置一个页面的表单提交地址为web.xml文件中配置的url-pattern

image

直接访问页面即可

Servlet中获取参数(预防乱码)

  • 获取参数的语法:request.getParameter(String var1);

  • Tomcat8解决乱码问题get、post

    • get请求乱码(配置文件中是server.xml已经默认了字符集为UTF-8,无需解决)

    • post,在获取参数时,设置获取参数时采用的编码。request.setCharacterEncoding("UTF-8");

  • Tomcat7解决乱码问题

    • get请求乱码的2种解决方式
      • (1)修改server.xml文件,在Connector 标签 中添加URIEncoding="utf-8"
      • (2)String(Request.getParameter("username").getBytes("ISO8859-1"), "UTF-8");
    • post请求乱码的解决方式同Tomcat8解决方式一致

Servlet的继承关系以及service方法

  • Servlet中的继承关系图
    image

  • 其中在接口Servlet中,看到了提供服务的service方法。

    • GenericServlet抽象类实现了Servlet接口,但是并没有重写service方法
      • HttpServlet抽象类继承了GenericServlet,重写了service方法
      • 实质上每次提供服务的都是service方法,(重写doGet和doPost方法也能够接收到请求的原因是因为HttpServlet中的service方法会通过请求方式调用doGet、doPost等方法)

Servlet的生命周期和Servlet的单例问题

  • 初始化状态,对应init()方法。注意:初始化前会通过反射创建Servlet对象,如果自定义的Servlet中将空参构造方法进行了私有将会直接抛出异常

  • 服务状态,对应service()方法。

  • 销毁状态,对应destory()方法


  • 在web.xml文件当中将同一个Servlet配置了多次,那么该Servlet对象就会被加载多次,变成多例模式。

  • 若是在web.xml文件中配置了一个Servlet并且仅配置了一个,那么就是单例模式,该Servlet的实例只会创建一次(需要注意线程安全问题,可以的话不要定义成员变量)。

Servlet的创建时机

  • 默认Servlet在第一次被访问时,才会进行初始化操作

  • 优点:提高了服务器的启动速度

  • 缺点:会影响第一次访问时的响应速度

  • 修改Servlet的初始化时机为跟随Tomcat容器运行时一起创建,修改web.xml,在servlet标签中添加
    <load-on-startup>1</load-on-startup>:该值最小为0,随意写一个数值,数值越小,创建的优先级越高

HTTP协议的请求信息与响应信息

  • HTTP协议是什么?
    HTTP超文本传输协议其实就是请求与相应的一个规则,请求方的请求按照这个协议规则,响应方的响应也按照这个协议规则。

请求信息包含3个部分

  • 请求行

    • 1、请求的方式
    • 2、请求的URL
    • 3、请求的协议(一般都是HTTP1.1)
  • 请求消息头:包含客户端要告诉服务器的信息

    • 浏览器型号、版本、能接收的内容类型、能接收的语言等等
  • 请求体(3种情况)

    • get(querystring)
    • post(form data)
    • json(request payload)

响应信息包含3个部分

  • 响应行

    • 1、协议
    • 2、响应状态码
    • 3、响应状态(ok等)
  • 响应消息头:包含服务器的信息,内容的媒体类型、编码、内容长度等

  • 响应体:响应的实际内容,比如html、js、css等资源

HTTP协议无状态问题的解决方案Session

  • 什么是无状态
    无状态:无论客户端访问了多少次服务端,服务端都无法识别客户端的身份。

  • 如何解决HTTP无状态的问题,通过Session会话跟踪技术

    • 当客户端第一次访问服务端的时候,将会为客户端分配一个唯一的SessionID

    • 当客户端再次访问服户端时,就会携带着这个SessionId访问,服务端就可以通过获取Session来判断客户端的身份

  • 获取Session的常用API

    • 获取Session,request.getSession();,当前客户端没有Session时为其创建一个
    • 获取Session,request.getSession(true);,当前客户端没有Session时为其创建一个
    • 获取Session,request.getSession(false);,当前客户端没有Session时返回null

请求转发与重定向

  • 请求转发

    • 客户端:只发送了一次请求
    • 服务端:内部可以进行多次请求转发
  • 重定向

    • 客户端:对于客户端来说,不止发送了一个请求
    • 服务端:相当于直接让客户端重新发送一个请求到指定的URL

Thymeleaf的快速入门

引入jar包

下载地址
image

编写一个Servlet视图解析器

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

创建一个Servlet继承该视图解析器

public class ThymeleafDemoServlet extends ViewBaseServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 直接跳转界面,这里相当于  /hello.html,因为刚刚配置视图解析器的时候有前缀和后缀
        super.processTemplate("hello", req, resp);
    }
}

使用视图解析器跳转的页面就可以使用thymeleaf标签了

  • html文档的开头
    <html xmlns:th="http://www.thymeleaf.org">

  • 常用的几个标签

1. 获取作用域中的变量
${request.变量值}、${session.变量值}

2. 编写路径
@{/css/a.css} 相当于找到项目web根路径下的css文件夹下的a.css

3. each循环
      <tr  th:each="user,userStat : ${list}">
        <td th:text="${user.userName}"></td> 
        <td th:text="${user.email}"></td> 
        <td th:text="${user.isAdmin}"></td> 
        <th th:text="${userStat.index}">当前迭代对象的index(从0开始计算)</th> 
        <th th:text="${userStat.count}"> 当前迭代对象的index(从1开始计算)</th> 
        <th th:text="${userStat.current.userName}">当前迭代变量</th> 
        <th th:text="${userStat.even}">是否偶数</th> 
        <th th:text="${userStat.odd}">是否偶数</th> 
        <th th:text="${userStat.first}">当前循环是否是第一个</th> 
        <th th:text="${userStat.last}">当前循环是否是最后一个</th> 
      </tr>

自定义究极简版的SpringMvc与Spring

自定义SpringMVC的DispatchServlet类

DispatchServlet所需要实现的功能

(1)接收**所有的客户端**请求
(2)通过客户端**请求路径**找到对应的控制器和方法,完成调用
(3)获取控制器执行方法后的返回值(String类型),进行**视图解析**工作

整体的思路如下:

(1)创建一个DispatchServlet类,继承上面写的试图解析器ViewBaseServlet()
(2)编写一个成员变量, 该变量为BeanFactory,作用是获取Spring容器中的bean
(2)重写init()方法
	- 调用父类的init()方法完成视图解析器的初始化
	- 完成BeanFactory的初始化,`beanFactory = new ClassPathXmlApplication();`
(3)重写service(HttpServletRequest request,HttpServletResponse response)方法
	- 通过request.getPathInfo()方法获取客户端的请求路径
	- 通过自定义的规则分割出请求的控制器以及方法
	- 通过beanFactory获取到需要请求的控制器
		- 再通过该控制器获取到所有的方法
		- 使用客户端请求中分割出的方法名与控制器中的**各方法名进行匹配**,如果匹配到了,则获取该方法中的**所有参数列表**(需要添加`-parameters`JAVA编译参数),通过参数列表中的名称和类型来进行**参数获取**后存储到一个Object数组中
(4)进行方法的调用
(5)获取到方法的返回值,通过该返回值进行视图解析

代码实现

import com.codestarts.io.BeanFactory;
import com.codestarts.io.ClassPathXmlApplication;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @author codeStars
 * @date 2022/8/25 15:05
 * 自定义SpringMvc的核心控制器DispatchServlet
 */
@WebServlet("/codestarts/*")
public class DispatchServlet extends ViewBaseServlet {
    private BeanFactory beanFactory;


    @Override
    public void init() throws ServletException {
        // 初始化模板引擎
        super.init();
        // 初始化spring容器
        beanFactory = new ClassPathXmlApplication();
    }

    /**
     * 注意,访问时: /控制器bean/方法名?参数即可,传参只考虑单值,以及Integer的判断
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // 设置编码
            request.setCharacterEncoding("UTF-8");

            // 获取客户端发送请求中的地址
            String pathInfo = request.getPathInfo();
            // 获取到需要访问的控制器
            int start = pathInfo.indexOf("/") + 1;
            int end = pathInfo.lastIndexOf("/");
            String controllerName = pathInfo.substring(start, end);

            // 获取需要调用的方法
            String methodName = pathInfo.substring(end + 1);

            // 通过容器获取对应的控制器完成调用
            Object controller = beanFactory.getBean(controllerName);

            // 获取到控制器所有的方法
            Method[] methods = controller.getClass().getMethods();

            for (Method method : methods) {
                if(method.getName().equals(methodName)) {
                    // 1. 获取参数,使用 Object[] params来获取
                    Parameter[] parameters = method.getParameters();
                    Object[] params = new Object[parameters.length];
                     // 获取参数
                    for (int i = 0; i < parameters.length; i++) {
                        // 获取单独的一个参数
                        Parameter parameter = parameters[i];
                        // 获取参数名
                        String paramName = parameter.getName();
                        // 判断参数名,根据参数名获取参数
                        if ("request".equals(paramName)) {
                            params[i] = request;
                        }else if ("response".equals(paramName)) {
                            params[i] = response;
                        }else if ("session".equals(paramName)) {
                            params[i] = request.getSession();
                        }else {
                            // 获取到请求中传递的参数
                            String paramValue = request.getParameter(paramName);
                            Object param = paramValue;

                            // 如果是Integer类型,则将String转换为Integer
                            if ("java.lang.Integer".equals(parameter.getType().getName())){
                                if (param != null) {
                                    param = Integer.parseInt(paramValue);
                                }
                            }
                            params[i] = param;
                        }
                    }
                    // 2. 执行方法
                    Object returnObj = method.invoke(controller, params);

                    // 3. 进行视图解析
                    String path = "";

                    if (returnObj != null) {
                        path = (String) returnObj;
                    }

                    if (path.startsWith("redirect:")) {
                        response.sendRedirect(path.substring("redirect:".length()));
                    }else {
                        super.processTemplate(path, request, response);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

自定义Spring容器,完成IOC控制反转与DI依赖注入

Spring容器需要实现的功能

(1)有一个Map容器,Key的类型为String,Value的类型为Object
(2)在src路径下创建一个applicationContext.xml文件,只需要在该xml文件中配置组件以及组件之间的依赖关系即可
(3)解析xml文件,将各个组件都加载进Map容器当中
(4)通过一个getBean(String id)的方法获取组件

整体编写思路

(1)创建一个BeanFactory接口,里面只有一个`Object getBean(String id)`的方法
(2)创建一个构造函数,在构造函数中完成数据的初始化
	- 通过DocumentBuilderFactory来获取到解析Xml的对象
	- 获取到Xml中的所有bean节点,再根据bean节点中记录的id,class来完成bean容器的第一次初始化
	- 再次获取到Xml中的所有bean节点,通过bean节点获取到其所有的子节点进行遍历,若是找到元素名为property的节点,则获取到其中的name跟ref完成父节点的依赖注入。

代码实现

Xml文件格式
<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <bean id="fruitDao" class="com.codestarts.dao.impl.FruitDaoImpl"></bean>

    <bean id="index" class="com.codestarts.controller.IndexController">
        <property name="fruitDao" ref="fruitDao"></property>
    </bean>
</beans>
BeanFactory与ClassPathXmlApplication的实现
  • BeanFactory.java
public interface BeanFactory {

    Object getBean(String id);
}
  • ClassPathXmlApplication.java
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author codeStars
 * @date 2022/8/26 9:30
 * 自定义Spring容器
 */
public class ClassPathXmlApplication implements BeanFactory {
    private static Map<String, Object> beanMap = new HashMap<>();

    public ClassPathXmlApplication () {
        try {
            InputStream applicationContextXml = this.getClass().getClassLoader().getResourceAsStream("application.xml");

            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

            Document parseXml = documentBuilder.parse(applicationContextXml);

            // 获取到所有的bean节点
            NodeList nodeList = parseXml.getElementsByTagName("bean");

            // 遍历所有的节点,并进行控制反转
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node item = nodeList.item(i);
                // 判断是否为元素节点
                if(item.getNodeType() == Node.ELEMENT_NODE) {
                    NamedNodeMap attributes = item.getAttributes();

                    String beanId = attributes.getNamedItem("id").getNodeValue();
                    Object bean = Class.forName(attributes.getNamedItem("class").getNodeValue()).newInstance();
                    beanMap.put(beanId, bean);
                }
            }

            // 再次遍历所有的bean节点,进行依赖注入
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node item = nodeList.item(i);

                // 获得所有bean节点下的子节点,判断为元素节点时,进行依赖注入
                NodeList childNodes = item.getChildNodes();
                for (int y = 0; y < childNodes.getLength(); y++) {
                    Node childNode = childNodes.item(y);
                    if(childNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(childNode.getNodeName())) {
                        // 获取到bean节点id
                        String currentBeanId = item.getAttributes().getNamedItem("id").getNodeValue();

                        NamedNodeMap attributes = childNode.getAttributes();
                        // 需要注入的属性名
                        String name = attributes.getNamedItem("name").getNodeValue();
                        // 需要注入的beanId
                        String ref = attributes.getNamedItem("ref").getNodeValue();

                        // 获取到需要被依赖注入的bean,以及需要被依赖注入的bean的属性
                        Object beanNode = beanMap.get(currentBeanId);
                        Field field = beanNode.getClass().getDeclaredField(name);
                        field.setAccessible(true);

                        // 获取到要被注入的组件
                        Object beanNodeElementObj = beanMap.get(ref);

                        // 注入进去,再重新存到Map容器
                        field.set(beanNode, beanNodeElementObj);
                        beanMap.put(currentBeanId, beanNode);
                    }
                }
            }
        } catch (Exception e) {
           throw new RuntimeException(e);
        }
    }


    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }
}
如何使用呢?
  • 编写一个Controller
public class IndexController {
    private FruitDao fruitDao = null;

    public void add(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("index: add");
    }
}
  • 如果想要访问该控制器的add方法,则只需要在浏览器中
    服务器路径/codestarts/index/add即可

Servlet的常用api

Servlet的初始化方法(2个)

  • Servlet的初始化方法有2个,分别为public void init() throws ServletException(),该方法用于我们进行一些自定义初始化操作

  • 还有一个init()方法,该方法会自动调用init()方法

public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}

获取自定义Servlet、ServletContext的配置信息

自定义Servlet

    • 通过注解或xml的方式定义参数
<servlet>
    <servlet-name>name</servlet-name>
    <init-param>
        <param-name>param1</param-name>
        <param-value>oneParam</param-value>
    </init-param>
</servlet>

或者

@WebServlet(initParams = { @WebInitParam(name = "param1",value = "onwParam") } )
  • 在Servlet获取到配置的参数
	String param1 = this.getInitParameter("param1");
	String param2 = this.getInitParameter("param2");

获取ServletContext的配置信息

  • 在web.xml文件中进行参数的配置
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>
  • 在Servlet中获取参数
    ServletContext servletContext1 = this.getServletContext();
    servletContext1.getInitParameter("view-prefix");

理解MVC

  • Model 模型,其中包含pojo/vo模型、业务层BO模型、持久层DAO、数据传输模型DTO等

  • View视图,用于将结果显示到页面上,完成与客户端的交互

  • Controller控制器,用于接收客户端的请求

业务层与持久层的关系及作用

  • 业务层与持久层的关系
      业务层BO中的一个业务方法,可能会调用多个持久层DAO中的方法来完成一个业务功能。

  • 业务层的作用
      业务层用于处理一个个的业务单元,例如一个业务叫做注册,一个业务叫做登录。而一个个的业务功能中都可能会调用多个不同的DAO,(此时应该考虑事物的原子性问题)

  • 持久层的作用
      持久层中的一个个不同的DAO通常用于执行一个个的单元操作,一个DAO方法只做一件事,那就是新增或修改、删除或更新。

IOC控制反转与DI依赖注入

  • IOC控制反转
      在以往项目当中,我们一个个类对象都是由我们程序员来控制它的生命周期的,例如定义为局部变量,则方法执行完毕销毁,定义为成员变量,则该类的示例没有引用指向时销毁。
      而IOC控制反转则是通过将对需要操作的对象(这里称之为一个个的bean)将其存储到一个容器中,又这个容器来对我们需要操作的bean进行统一的管理,我们将这种行为称之为IOC控制反转。

  • DI依赖注入
      通常与IOC控制反转一同运用,在将我们需要操作的bean对象都交于IOC容器管理时,一个个bean对象中的成员变量的引用可能是其他在容器中的bean对象。
      那么能不能程序在将bean对象添加到IOC容器的时候,顺便将一个个成员变量赋值呢,我们将这种行为称之为依赖注入。

Filter过滤器

过滤器的作用

   在一个JAVAWEB程序中,我们需要进行一些容易的行为时,可以采用过滤器。过滤器可以在调用指定的Servlet之前、以及之后进行一系列的行为。注意是在Servlet调用之前拦截到、以及Servlet返回结果到View视图层时再次拦截。

过滤器的使用

  编写一个JAVA类,实现Filter接口(注意是在Servlet包下的)。重写其中的3个方法。

/**
 * @author codeStars
 * @date 2022/8/26 13:29
 * 拦截/codestarts/开头的所有请求
 */
@WebFilter(urlPatterns = "/codestarts/*")
public class CharacterEncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("这是初始化方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Servlet调用之前");
        
        // 放行到下一个Filter、如果没有下一个Filter时,则到了Servlet调用的时候了
        filterChain.doFilter(servletRequest, servletResponse);
        
        // 方法调用之后
        System.out.println("Servlet调用之后");
    }

    @Override
    public void destroy() {
        System.out.println("这是销毁方法");
    }
}

过滤链

  • 如果项目中存在多个Filter过滤器,并且都拦截了同一个请求,那么他们的执行顺序是怎样的呢?
    • 如果是以注解的方式配置,则会通过全类名来进行字符串大小排序,从小到大依次拦截。

    • 如果是xml配置的方式,则会根据配置的先后顺序进行拦截。

事物管理

思考事物管理的代码应该写在哪

  • 首先是想到写在DAO持久层,但是DAO仅仅是单纯的增删改查中的任意一项,并且一个个业务代码的编写应该是在业务层,一个功能很可能需要使用多个DAO,因此DAO层不考虑

  • 其次是想到写在service业务层中编写事物管理的代码,这个时候可以解决事物的原子性问题,在执行多个DAO之前,进行事物的管理。注意要让所有的DAO都使用同一个连接。但是问题在于:难道每一个业务方法都进行事务的管理吗?因此业务层进行事物管理也不太理想。

  • 最终想到了定义一个OpenSessionInViewFilter过滤器,在该过滤器中统一进行事物的管理。

实现如上设想的前提

  • 需要让一个事物中的所有Dao都使用同一个连接(使用ThreadLocal)

  • 不能让业务层、持久层对自身的异常直接进行try catch内部处理,不然会导致Filter过滤器无法捕获到异常

  • 实现思路
    (1)定义一个OpenSessionInViewFilter过滤器,doFilter()方法中进行所有代码的try catch捕获,放行前开启事物、放行后提交事物、捕获到异常则回滚事物
    (2)创建一个TransactionManager类,其中进行事物的开启、关闭、回滚
    (3)创建一个ConnUtils类,用于通过数据源获取连接等,每个线程需要唯一的一个连接(ThreadLocal)。

一共有8个监听器(了解)

ServletContextListener 监听Application的创建与销毁
HttpSessionListener    监听Session的创建与销毁
ServletRequestListener 监听Request对象的创建与销毁

ServletContextAttributeListener 监听Application作用域添加、删除、修改元素
HttpSessionAttributeListener 监听Session作用域添加、删除、修改元素
ServletRequestAttributeListener 监听request作用域添加、删除、修改元素

httpSessionActivationListener 监听session作用域中对象的钝化(序列化)与活化(反序列化)

httpSessionBindingListener 监听session与对象的绑定

ServletContextListener的应用(创建SpringIOC容器)

@WebListener
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // 获取到ServletContext,通过web.xml文件中的配置获取xml配置文件的名称
        ServletContext servletContext = servletContextEvent.getServletContext();
        String applicationXmlName = servletContext.getInitParameter("contextConfigLocation");
        // 创建IOC容器
        BeanFactory beanFactory = new ClassPathXmlApplication(applicationXmlName);

        // 添加到Application作用域
        servletContext.setAttribute("beanFactory", beanFactory);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {}
}

Cookie的作用

  Cookie用于给客户端发送一部分数据,存储到客户端当中,之后客户端再次请求服务器时,可以携带这部分数据访问,服务器可以根据这部分数据进行一系列的判断等。

  • 应用场景

    • 记住密码,客户端在第一次登录时,将客户端发送的用户名和密码响应给客户端,保存到客户端的Cookie当中下一次客户端再次访问时,服务器就可以获取到用户名和密码,从而直接展示在页面当中。
    • 十天免登录
  • 使用演示

    // 创建1个Cookie,响应给客户端
    Cookie usernameCookie = new Cookie("username","张三");
    // 设置超时时间,以秒为单位,10天
    usernameCookie.setMaxAge(60 * 60 * 24 * 10);
    // 设置指定路径客户端才会发送该Cookie
    usernameCookie.setPath("/codestarts/");
    // 添加cookie到响应中
    response.addCookie(usernameCookie);

    // 获取客户端发送过来的Cookie
    Cookie[] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
        System.out.println(cookie.getName()  + "--" + cookie.getValue());
    }

    // 随便响应点内容
    response.setCharacterEncoding("UTF-8");
    response.getWriter().println("Cookie保存成功了");

kaptcha验证码的使用

  • 引入jar包,下载地址

  • 在web.xml文件中配置(其实就是一个Servlet)

    <servlet>
        <servlet-name>kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>kaptcha</servlet-name>
        <url-pattern>/kaptcha.jpg</url-pattern>
    </servlet-mapping>
  • 在web界面中的编写一个img标签,src写Servlet的请求路径
<img src="kaptcha.jpg" alt="">
  • 在Servlet当中可以通过Session作用域获取
Object kaptcha_session_key = session.getAttribute("KAPTCHA_SESSION_KEY");

Vue的快速入门

绑定元素属性

  • 插值表达式{{}}与元素绑定
-- javascript代码
    <script type="text/javascript" src="js/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: "#app",
                data: {
                    msg: "张三",
                    msg2: "李四"
                }
            });
        }
    </script>

-- html代码
	<div id="app">
		<p>{{msg}}</p>
		这是一个文本框:<input type="text" v-bind:value="msg2">
	</div>

双向绑定数据

-- javascript代码

<script type="text/javascript" src="js/vue.js"></script>
<script>
    var app;
    window.onload = function(){
        app = new Vue({
            el: "#app",
            data: {
                msg: "张三",
            }
        });
    }
    function alertMsg() {
        alert(app.msg);
    }
</script>

-- html代码
<div id="app">
    这是一个文本框:<input type="text" v-model:value="msg"><br>
	
    <input type="button" value="点我即可查看当前msg的值" onclick="alertMsg()">
</div>

条件渲染

// javascript代码
window.onload = function(){
    var app = new Vue({
        el: "#app",
        data: {
            num: 1,
        }
    });
}

-- html代码
<div id="app">
    这是一个文本框:<input type="text" v-model:value="num"><br>
    <!-- 如果num=1,则显示该行,注意会删除该div,注意if和else之间的不能有其他的节点 -->
    <div v-if="num==1" style="width: 40px;height: 40px;background: #1E9FFF"></div>
    <div v-else style="width: 40px;height: 40px;background: #00FF00"></div>

    <!-- 如果num=1,则显示该行,通过节点的display属性控制 -->
    <div v-show="num==1" style="width: 40px;height: 40px;background: #5FB878"></div>
</div>

列表渲染

// javascript代码
window.onload = function(){
    var app = new Vue({
        el: "#app",
        data: {
            userList: [
                {uid:1, uname:"张三", pwd:"123"},
                {uid:2, uname:"王五", pwd:"333"},
                {uid:3, uname:"赵六", pwd:"222"},
                {uid:4, uname:"二花", pwd:"111"}
            ]
        }
    });
}

// html代码
<div id="app">
    <ul v-for="user in userList">
        <li>{{user.uid}}</li>
        <li>{{user.uname}}</li>
        <li>{{user.pwd}}</li>
    </ul>
</div>

事件驱动

// javascript代码
window.onload = function(){
    var app = new Vue({
        el: "#app",
        methods: {
            firstVueMethod: function () {
                alert("学习vue写的第一个方法");
            }
        }
    });
}

// html 代码
<div id="app">
    <input type="button" v-on:click="firstVueMethod" value="点我即可调用方法"/>
</div>

侦听属性

// 这是javascript代码
window.onload = function(){
    var app = new Vue({
        el: "#app",
        data: {
            msg: "我是信息"
        },
        watch: {
            msg: function (newMsg) {
                alert("msg发生了改变,新的值为:" + newMsg);
            }
        }
    });
}

// 这是html代码
<div id="app">
    这里是用双向绑定,绑定了msg属性:<input type="text" v-model:value="msg">
</div>

Vue对象生命周期(钩子函数)

// javascript代码
window.onload = function(){
    var app = new Vue({
        el: "#app",
        data: {
            msg: "我是信息"
        },
        beforeCreate: function () {
            console.log("Vue对象创建之前:" + this.msg);
        },
        created: function () {
            console.log("Vue对象创建之后:" + this.msg);
        },
        // 这里可以通过浏览器的调试工具验证
        beforeMount: function () {
            console.log("将data数据中的值挂载到页面之前" + this.msg);
        },
        mounted: function () {
            console.log("将data数据中的值挂载到页面之后" + this.msg);
        },
        beforeUpdate:function () {
            console.log("数据被更新之前" + this.msg);
        },
        updated:function () {
            console.log("数据被更新之后" + this.msg);
        }
    });
}


-- html代码
<div id="app">
    看看值的变化:<h2>{{msg}}</h2>
    <input type="text" v-model="msg">
</div>
posted @ 2022-08-31 11:27  CodeStars  阅读(149)  评论(0编辑  收藏  举报