Tomcat

Web 应⽤服务器:Tomcat、Jboos、Weblogic、Jetty

  • 安装 Tomcat
    1、官⽹下载压缩⽂件。https://tomcat.apache.org/download-90.cgi

    2、解压缩。
    bin:存放各个平台下启动和停⽌ Tomcat 服务的脚本⽂件。
    conf:存放各种 Tomcat 服务器的配置⽂件。
    lib:存放 Tomcat 服务器所需要的 jar。
    logs:存放 Tomcar 服务运⾏的⽇志。
    temp:Tomcat 运⾏时的临时⽂件。
    webapps:存放允许客户端访问的资源(Java 程序)。
    work:存放 Tomcat 将 JSP 转换之后的 Servlet ⽂件。

IDEA 集成 Tomcat

1、创建 Java Web ⼯程。






Servlet

  • 什么是 Servlet?
    Servlet 是 Java Web 开发的基⽯,与平台⽆关的服务器组件,它是运⾏在 Servlet 容器/Web 应⽤服务
    器/Tomcat,负责与客户端进⾏通信。
    Servlet 的功能:
    1、创建并返回基于客户请求的动态 HTML ⻚⾯。
    2、与数据库进⾏通信。
  • 如何使⽤ Servlet?
    Servlet 本身是⼀组接⼝,⾃定义⼀个类,并且实现 Servlet 接⼝,这个类就具备了接受客户端请求以及
    做出响应的功能。
package com.southwind.servlet;
import javax.servlet.*;
import java.io.IOException;
public class MyServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponseservletResponse) throws ServletException, IOException {String id = servletRequest.getParameter("id");System.out.println("我是Servlet,我已经接收到了客户端发来的请求,参数是"+id);servletResponse.setContentType("text/html;charset=UTF-8");servletResponse.getWriter().write("客户端你好,我已接收到你的请求");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}

浏览器不能直接访问 Servlet ⽂件,只能通过映射的⽅式来间接访问 Servlet,映射需要开发者⼿动配
置,有两种配置⽅式。

  • 基于 XML ⽂件的配置⽅式。
<servlet><servlet-name>hello</servlet-name><servlet-class>com.southwind.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>hello</servlet-name><url-pattern>/demo2</url-pattern>
</servlet-mapping>
  • 基于注解的⽅式。
@WebServlet("/demo2")
public class HelloServlet implements Servlet {}

上述两种配置⽅式结果完全⼀致,将 demo2 与 HelloServlet 进⾏映射,即在浏览器地址栏中直接访问
demo 就可以映射到 HelloServlet。

Servlet 的⽣命周期

1、当浏览器访问 Servlet 的时候,Tomcat 会查询当前 Servlet 的实例化对象是否存在,如果不存在,
则通过反射机制动态创建对象,如果存在,直接执⾏第 3 步。
2、调⽤ init ⽅法完成初始化操作。
3、调⽤ service ⽅法完成业务逻辑操作。
4、关闭 Tomcat 时,会调⽤ destory ⽅法,释放当前对象所占⽤的资源。
反射机制:(如下图)

Servlet 的⽣命周期⽅法:⽆参构造函数、init、service、destory
1、⽆参构造函数只调⽤⼀次,创建对象。
2、init 只调⽤⼀次,初始化对象。
3、service 调⽤ N 次,执⾏业务⽅法。
4、destory 只调⽤⼀次,卸载对象。

ServletConfig

该接⼝是⽤来描述 Servlet 的基本信息的。
getServletName() 返回 Servlet 的名称,全类名(带着包名的类名)
getInitParameter(String key) 获取 init 参数的值(web.xml)

getInitParameterNames() 返回所有的 initParamter 的 name 值,⼀般⽤作遍历初始化参数
getServletContext() 返回 ServletContext 对象,它是 Servlet 的上下⽂,整个 Servlet 的管理者。
ServletConfig 和 ServletContext 的区别:
ServletConfig 作⽤于某个 Servlet 实例,每个 Servlet 都有对应的 ServletConfig,ServletContext 作⽤
于整个 Web 应⽤,⼀个 Web 应⽤对应⼀个 ServletContext,多个 Servlet 实例对应⼀个
ServletContext。
⼀个是局部对象,⼀个是全局对象。

Servlet 的层次结构

Servlet ====> GenericServlet ====> HttpServlet
HTTP 请求有很多种类型,常⽤的有四种:

GET 读取
POST 保存
PUT 修改
DELETE 删除

GenericServlet 实现 Servlet 接⼝,同时为它的⼦类屏蔽了不常⽤的⽅法,⼦类只需要重写 service ⽅
法即可。
HttpServlet 继承 GenericServlet,根据请求类型进⾏分发处理,GET 进⼊ doGET ⽅法,POST 进⼊
doPOST ⽅法。
开发者⾃定义的 Servlet 类只需要继承 HttpServlet 即可,重新 doGET 和 doPOST。

package com.southwind.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {resp.getWriter().write("GET");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {resp.getWriter().write("POST");}
}

JSP

JSP 本质上就是⼀个 Servlet,JSP 主要负责与⽤户交互,将最终的界⾯呈现给⽤户,
HTML+JS+CSS+Java 的混合⽂件。
当服务器接收到⼀个后缀是 jsp 的请求时,将该请求交给 JSP 引擎去处理,每⼀个 JSP ⻚⾯第⼀次被访
问的时候,JSP 引擎会将它翻译成⼀个 Servlet ⽂件,再由 Web 容器调⽤ Servlet 完成响应。
单纯从开发的⻆度看,JSP 就是在 HTML 中嵌⼊ Java 程序。
具体的嵌⼊⽅式有 3 种:
1、JSP 脚本,执⾏ Java 逻辑代码

<% Java代码 %>

2、JSP 声明:定义 Java ⽅法

<%!声明 Java ⽅法
%>

3、JSP 表达式:把 Java 对象直接输出到 HTML ⻚⾯中

<%=Java变量 %>
<%!public String test(){return "HelloWorld";
}
%>
<%
String str = test();
%>
<%=str%>

JSP内置对象 9 个

1、request:表示⼀次请求,HttpServletRequest。
2、response:表示⼀次响应,HttpServletResponse。
3、pageContext:⻚⾯上下⽂,获取⻚⾯信息,PageContext。
4、session:表示⼀次会话,保存⽤户信息,HttpSession。
5、application:表示当前 Web 应⽤,全局对象,保存所有⽤户共享信息,ServletContext。
6、config:当前 JSP 对应的 Servlet 的 ServletConfig 对象,获取当前 Servlet 的信息。
7、out:向浏览器输出数据,JspWriter。
8、page:当前 JSP 对应的 Servlet 对象,Servlet。
9、exception:表示 JSP ⻚⾯发⽣的异常,Exception。
常⽤的是 request、response、session、application、pageContext

request 常⽤⽅法:
1、String getParameter(String key) 获取客户端传来的参数。
2、void setAttribute(String key,Object value) 通过键值对的形式保存数据。(服务端内部传递参数)
3、Object getAttribute(String key) 通过 key 取出 value。
4、RequestDispatcher getRequestDispatcher(String path) 返回⼀个 RequestDispatcher 对象,该对象的 forward ⽅法⽤于请求转发。
5、String[] getParameterValues() 获取客户端传来的多个同名参数。
6、void setCharacterEncoding(String charset) 指定每个请求的编码。

HTTP 请求状态码

200:正常
404:资源找不到
400:请求类型不匹配
500:Java 程序抛出异常

response 常⽤⽅法:
1、sendRedirect(String path) 重定向,⻚⾯之间的跳转。
转发 getRequestDispatcher 和重定向 sendRedirect 的区别:
转发是将同⼀个请求传给下⼀个⻚⾯,重定向是创建⼀个新的请求传给下⼀个⻚⾯,之前的请求结束⽣
命周期。
转发:同⼀个请求在服务器之间传递,地址栏不变,也叫服务器跳转。
重定向:由客户端发送⼀次新的请求来访问跳转后的⽬标资源,地址栏改变,也叫客户端跳转。
如果两个⻚⾯之间需要通过 request 来传值,则必须使⽤转发,不能使⽤重定向。
⽤户登录,如果⽤户名和密码正确,则跳转到⾸⻚(转发),并且展示⽤户名,否则重新回到登陆⻚⾯
(重定向)。

Session

⽤户会话
服务器⽆法识别每⼀次 HTTP 请求的出处(不知道来⾃于哪个终端),它只会接受到⼀个请求信号,所
以就存在⼀个问题:将⽤户的响应发送给其他⼈,必须有⼀种技术来让服务器知道请求来⾃哪,这就是
会话技术。
会话:就是客户端和服务器之间发⽣的⼀系列连续的请求和响应的过程,打开浏览器进⾏操作到关闭浏
览器的过程。
会话状态:指服务器和浏览器在会话过程中产⽣的状态信息,借助于会话状态,服务器能够把属于同⼀次会话的⼀系列请求和响应关联起来。
实现会话有两种⽅式:

  • session
  • cookie

属于同⼀次会话的请求都有⼀个相同的标识符,sessionID

session 常⽤的⽅法:
String getId() 获取 sessionID
void setMaxInactiveInterval(int interval) 设置 session 的失效时间,单位为秒
int getMaxInactiveInterval() 获取当前 session 的失效时间
void invalidate() 设置 session ⽴即失效
void setAttribute(String key,Object value) 通过键值对的形式来存储数据
Object getAttribute(String key) 通过键获取对应的数据
void removeAttribute(String key) 通过键删除对应的数据

Cookie

Cookie 是服务端在 HTTP 响应中附带传给浏览器的⼀个⼩⽂本⽂件,⼀旦浏览器保存了某个 Cookie,
在之后的请求和响应过程中,会将此 Cookie 来回传递,这样就可以通过 Cookie 这个载体完成客户端
和服务端的数据交互。

  • 创建 Cookie
Cookie cookie = new Cookie("name","tom");
response.addCookie(cookie);
  • 读取 Cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie:cookies){out.write(cookie.getName()+":"+cookie.getValue()+"<br/>");
}

Cookie 常⽤的⽅法
void setMaxAge(int age) 设置 Cookie 的有效时间,单位为秒
int getMaxAge() 获取 Cookie 的有效时间
String getName() 获取 Cookie 的 name
String getValue() 获取 Cookie 的 value

Session 和 Cookie 的区别

session:保存在服务器
保存的数据是 Object
会随着会话的结束⽽销毁
保存重要信息
cookie:保存在浏览器
保存的数据是 String
可以⻓期保存在浏览器中,⽆会话⽆关
保存不重要信息

存储⽤户信息:
session

setAttribute("name","admin")   //存
getAttribute("name")   //取

⽣命周期:服务端:只要 WEB 应⽤重启就销毁,客户端:只要浏览器关闭就销毁。
退出登录:session.invalidate()

cookie

response.addCookie(new Cookie(name,"admin"))  //存Cookie[] cookies = request.getCookies();  //取
for (Cookie cookie:cookies){if(cookie.getName().equals("name")){out.write("欢迎回来"+cookie.getValue());}
}

⽣命周期:不随服务端的重启⽽销毁,客户端:默认是只要关闭浏览器就销毁,我们通过 setMaxAge()
⽅法设置有效期,⼀旦设置了有效期,则不随浏览器的关闭⽽销毁,⽽是由设置的时间来决定。
退出登录:setMaxAge(0)

JSP 内置对象作⽤域

4个
page、request、session、application
setAttribute、getAttribute
page 作⽤域:对应的内置对象是 pageContext。
request 作⽤域:对应的内置对象是 request。
session 作⽤域:对应的内置对象是 session。
application 作⽤域:对应的内置对象是 application。

page < request < session < application

page 只在当前⻚⾯有效。
request 在⼀次请求内有效。
session 在⼀次会话内有效。
application 对应整个 WEB 应⽤的。

  • ⽹站访问量统计
<%Integer count = (Integer) application.getAttribute("count");if(count == null){count = 1;application.setAttribute("count",count);}else{count++;application.setAttribute("count",count);}
%>
您是当前的第<%=count%>位访客

EL 表达式

Expression Language 表达式语⾔,替代 JSP ⻚⾯中数据访问时的复杂编码,可以⾮常便捷地取出域对
象(pageContext、request、session、application)中保存的数据,前提是⼀定要先 setAttribute,
EL 就相当于在简化 getAttribute
${变量名} 变量名就是 setAttribute 对应的 key 值。

1、EL 对于 4 种域对象的默认查找顺序:

pageContext ====> request ====> session ====> application

按照上述的顺序进⾏查找,找到⽴即返回,在 application 中也⽆法找到,则返回 null

2、指定作⽤域进⾏查找
pageContext:${pageScope.name}
request:${requestScope.name}
session:${sessionScope.name}
application:${applicationScope.name}

数据级联:

<%
// pageContext.setAttribute("name","page");
// request.setAttribute("name","request");
// session.setAttribute("name","session");
// application.setAttribute("name","application");User user = new User(1,"张三",86.5,new Address(1,"⼩寨"));System.out.println(user.toString());pageContext.setAttribute("user",user);
%><table><tr><th>编号</th><th>姓名</th><th>成绩</th><th>地址</th></tr><tr><td>${user.id}</td><td>${user.name}</td><td>${user.score}</td><td>${user.address}</td></tr></table>

${user[“id”]}

EL 执⾏表达式:

${num1&&num2}
&& || ! < > <= <= ==
&& and
|| or
! not
== eq
!= ne
< lt
> gt
<= le
>= ge
empty  //变量为 null,⻓度为0的String,size为0的集合


JSTL

JSP Standard Tag Library JSP 标准标签库,JSP 为开发者提供的⼀系列的标签,使⽤这些标签可以完成
⼀些逻辑处理,⽐如循环遍历集合,让代码更加简洁,不再出现 JSP 脚本穿插的情况。
实际开发中 EL 和 JSTL 结合起来使⽤,JSTL 侧重于逻辑处理,EL 负责展示数据。

JSTL 的使⽤
1、需要导⼊ jar 包(两个 jstl.jar standard.jar)存放的位置 web/WEB-INF
2、在 JSP ⻚⾯开始的地⽅导⼊ JSTL 标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

3、在需要的地⽅使⽤

<c:forEach items="${list}" var="user"><tr><td>${user.id}</td><td>${user.name}</td><td>${user.score}</td><td>${user.address.value}</td></tr>
</c:forEach>

JSTL 优点:
1、提供了统⼀的标签
2、可以⽤于编写各种动态功能

  • 核⼼标签库常⽤标签:

set、out、remove、catch

set:向域对象中添加数据

<%requset.setAttribute(key,value)
%>
<c:set var="name" value="tom" scope="request"></c:set>
${requestScope.name}
<%
User user = new User(1,"张三",66.6,new Address(1,"科技路"));
request.setAttribute("user",user);
%>
${user.name}
<hr/>
<c:set target="${user}" property="name" value="李四"></c:set>
${user.name}

out:输出域对象中的数据

<c:set var="name" value="tom"></c:set>
<c:out value="${name}" default="未定义"></c:out>

remove:删除域对象中的数据

<c:remove var="name" scope="page"></c:remove>
<c:out value="${name}" default="未定义"></c:out>

catch:捕获异常

<c:catch var="error"><%int a = 10/0;%>
</c:catch>
${error}
  • 条件标签:if choose
<c:set var="num1" value="1"></c:set>
<c:set var="num2" value="2"></c:set>
<c:if test="${num1>num2}">ok</c:if>
<c:if test="${num1<num2}">fail</c:if>
<hr/>
<c:choose><c:when test="${num1>num2}">ok</c:when><c:otherwise>fail</c:otherwise>
</c:choose>
  • 迭代标签:forEach
<c:forEach items="${list}" var="str" begin="2" end="3" step="2"
varStatus="sta">${sta.count}、${str}<br/>
</c:forEach>

格式化标签库常⽤的标签:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><%
request.setAttribute("date",new Date());
%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss">
</fmt:formatDate><br/>
<fmt:formatNumber value="32145.23434" maxIntegerDigits="2"
maxFractionDigits="3"></fmt:formatNumber>

函数标签库常⽤的标签:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %><%
request.setAttribute("info","Java,C");
%>
${fn:contains(info,"Python")}<br/>
${fn:startsWith(info, "Java")}<br/>
${fn:endsWith(info, "C")}<br/>
${fn:indexOf(info, "va")}<br/>
${fn:replace(info, "C","Python")}<br/>
${fn:substring(info, 2, 3)}<br/>
${fn:split(info, ",")[0]}-${fn:split(info, ",")[1]}

过滤器 Filter

功能:
1、⽤来拦截传⼊的请求和传出的响应。
2、修改或以某种⽅式处理正在客户端和服务端之间交换的数据流。
如何使⽤?
与使⽤ Servlet 类似,Filter 是 Java WEB 提供的⼀个接⼝,开发者只需要⾃定义⼀个类并且实现该接⼝
即可。

package com.southwind.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, seservletResponse, FilterChain filterChain) throws IOException, ServletException{servletRequest.setCharacterEncoding("UTF-8");filterChain.doFilter(servletRequest,servletResponse);}
}

web.xml 中配置 Filter

<filter><filter-name>charcater</filter-name><filter-class>com.southwind.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping><filter-name>charcater</filter-name><url-pattern>/login</url-pattern><url-pattern>/test</url-pattern>
</filter-mapping>

【注意】:doFilter ⽅法中处理完业务逻辑之后,必须添加filterChain.doFilter(servletRequest,servletResponse);
否则请求/响应⽆法向后传递,⼀直停留在过滤器中。

Filter 的⽣命周期

当 Tomcat 启动时,通过反射机制调⽤ Filter 的⽆参构造函数创建实例化对象,同时调⽤ init ⽅法实现
初始化,doFilter ⽅法调⽤多次,当 Tomcat 服务关闭的时候,调⽤ destory 来销毁 Filter 对象。
⽆参构造函数:只调⽤⼀次,当 Tomcat 启动时调⽤(Filter ⼀定要进⾏配置)
init ⽅法:只调⽤⼀次,当 Filter 的实例化对象创建完成之后调⽤
doFilter:调⽤多次,访问 Filter 的业务逻辑都写在 Filter 中
destory:只调⽤⼀次,Tomcat 关闭时调⽤。

同时配置多个 Filter,Filter 的调⽤顺序是由 web.xml 中的配置顺序来决定的,写在上⾯的配置先调
⽤,因为 web.xml 是从上到下顺序读取的。

<filter><filter-name>my</filter-name><filter-class>com.southwind.filter.MyFilter</filter-class>
</filter>
<filter-mapping><filter-name>my</filter-name><url-pattern>/login</url-pattern>
</filter-mapping>
<filter><filter-name>charcater</filter-name><filter-class>com.southwind.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping><filter-name>charcater</filter-name><url-pattern>/login</url-pattern><url-pattern>/test</url-pattern>
</filter-mapping>

1、MyFilter
2、CharacterFilter

也可以通过注解的⽅式来简化 web.xml 中的配置

<filter><filter-name>my</filter-name><filter-class>com.southwind.filter.MyFilter</filter-class>
</filter>
<filter-mapping><filter-name>my</filter-name><url-pattern>/login</url-pattern>
</filter-mapping>

等于

@WebFilter("/login")
public class MyFilter implements Filter {}

Filter 的使⽤场景

实际开发中 Filter 的使⽤场景:
1、统⼀处理中⽂乱码。
2、屏蔽敏感词。

package com.southwind.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/test")
public class WordFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain filterChain) throws IOException, ServletException
{servletRequest.setCharacterEncoding("UTF-8");//将"敏感词"替换成"***"String name = servletRequest.getParameter("name");name = name.replaceAll("敏感词","***");servletRequest.setAttribute("name",name);filterChain.doFilter(servletRequest,servletResponse);}
}
package com.southwind.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {String name = (String) req.getAttribute("name");System.out.println("servlet:"+name);}
}

3、控制资源的访问权限。

package com.southwind.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/download.jsp")
public class DownloadFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain filterChain) throws IOException, ServletException
{HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;HttpSession session = request.getSession();String name = (String) session.getAttribute("name");if(name == null){//不是登录状态response.sendRedirect("/login.jsp");}else{filterChain.doFilter(servletRequest,servletResponse);}}
}

⽂件上传下载

  • JSP
    1、input 的 type 设置为 file
    2、form 表单的 method 设置 post,get 请求会将⽂件名传给服务端,⽽不是⽂件本身
    3、form 表单的 enctype 设置 multipart/form-data,以⼆进制的形式传输数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><form enctype="multipart/form-data" action="/upload" method="post"><input name="desc" type="text"/><br/><input name="text" type="file"/><br/><input type="submit" value="上传"/></form>
</body>
</html>
  • Servlet
    fileupload 组件可以将所有的请求信息都解析成 FileIteam 对象,可以通过对 FileItem 对象的操作完成上传,⾯向对象的思想。
package com.southwind.servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {// //通过输⼊流获取客户端传来的数据流// InputStream inputStream = req.getInputStream();// Reader reader = new InputStreamReader(inputStream);// BufferedReader bufferedReader = new BufferedReader(reader);// //通过输出流将数据流输出到本地硬盘// //获取⽂件夹的绝对路径// String path = req.getServletContext().getRealPath("file/copy.txt");// OutputStream outputStream = new FileOutputStream(path);// Writer writer = new OutputStreamWriter(outputStream);// BufferedWriter bufferedWriter = new BufferedWriter(writer);// String str = "";// while((str = bufferedReader.readLine())!=null){// System.out.println(str);// bufferedWriter.write(str);// }// bufferedWriter.close();// writer.close();// outputStream.close();// bufferedReader.close();// reader.close();// inputStream.close();try {DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);List<FileItem> list = servletFileUpload.parseRequest(req);for(FileItem fileItem : list){if(fileItem.isFormField()){String name = fileItem.getFieldName();String value = fileItem.getString("UTF-8");System.out.println(name+":"+value);}else{String fileName = fileItem.getName();long size = fileItem.getSize();System.out.println(fileName+":"+size+"Byte");InputStream inputStream = fileItem.getInputStream();// Reader reader = new InputStreamReader(inputStream);// BufferedReader bufferedReader = new BufferedReader(reader);String path = req.getServletContext().getRealPath("file/"+fileName);OutputStream outputStream = new FileOutputStream(path);// Writer writer = new OutputStreamWriter(outputStream);// BufferedWriter bufferedWriter = new BufferedWriter(writer);int temp = 0;while((temp = inputStream.read())!=-1){outputStream.write(temp);}// bufferedWriter.close();// writer.close();outputStream.close();// bufferedReader.close();// reader.close();inputStream.close();System.out.println("上传成功");}}} catch (FileUploadException e) {e.printStackTrace();}}
}

⽂件下载

package com.southwind.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {String type = req.getParameter("type");String fileName = "";switch (type){case "png":fileName = "1.png";break;case "txt":fileName = "test.txt";break;}//设置响应⽅式resp.setContentType("application/x-msdownload");//设置下载之后的⽂件名resp.setHeader("Content-Disposition","attachment;filename="+fileName);//获取输出流OutputStream outputStream = resp.getOutputStream();String path = req.getServletContext().getRealPath("file/"+fileName);InputStream inputStream = new FileInputStream(path);int temp = 0;while((temp=inputStream.read())!=-1){outputStream.write(temp);}inputStream.close();outputStream.close();}
}

Ajax

Asynchronous JavaScript And XML:异步的 JavaScript 和 XML
AJAX 不是新的编程,指的是⼀种交互⽅式,异步加载,客户端和服务器的数据交互更新在局部⻚⾯的
技术,不需要刷新整个⻚⾯(局部刷新)
优点:
1、局部刷新,效率更⾼
2、⽤户体验更好

【注】:同步:(打电话);异步:(发微信)

基于 jQuery 的 A JAX:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><script type="text/javascript" src="js/jquery-3.3.1.min.js"></script><script type="text/javascript">$(function(){var btn = $("#btn");btn.click(function(){$.ajax({url:'/test',type:'post',data:'id=1',dataType:'text',success:function(data){var text = $("#text");text.before("<span>"+data+"</span><br/>");}});});})</script>
</head>
<body><input id="text" type="text"/><br/><input id="btn" type="button" value="提交"/>
</body>
</html>

不能⽤表单提交请求,改⽤ jQuery ⽅式动态绑定事件来提交。
Servlet 不能跳转到 JSP,只能将数据返回

package com.southwind.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {String id = req.getParameter("id");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}String str = "Hello World";resp.getWriter().write(str);}
}

传统的 WEB 数据交互 VS AJAX 数据交互

  • 客户端请求的⽅式不同:
    传统:浏览器发送同步请求 (form、a)
    AJAX:异步引擎对象发送异步请求
  • 服务器响应的⽅式不同:
    传统:响应⼀个完整 JSP ⻚⾯(视图)
    AJAX:响应需要的数据
  • 客户端处理⽅式不同:
    传统:需要等待服务器完成响应并且重新加载整个⻚⾯之后,⽤户才能进⾏后续的操作
    AJAX:动态更新⻚⾯中的局部内容,不影响⽤户的其他操作

AJAX 原理

基于 jQuery 的 AJAX 语法

$.ajax({属性})
常⽤的属性参数:
url:请求的后端服务地址
type:请求⽅式,默认 get
data:请求参数
dataType:服务器返回的数据类型,text/json
success:请求成功的回调函数
error:请求失败的回调函数
complete:请求完成的回调函数(⽆论成功或者失败,都会调⽤)

JSON

JavaScript Object Notation,⼀种轻量级数据交互格式,完成 js 与 Java 等后端开发语⾔对象数据之间
的转换。
客户端和服务器之间传递对象数据,需要⽤ JSON 格式。

package com.southwind.entity;
public class User {private Integer id;private String name;private Double score;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getScore() {return score;}public void setScore(Double score) {this.score = score;}public User(Integer id, String name, Double score) {this.id = id;this.name = name;this.score = score;}
}
User user = new User(1,"张三",96.5)
var user = {id:1,name:"张三",score:96.5
}
package com.southwind.servlet;
import com.southwind.entity.User;
import net.sf.json.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {User user = new User(1,"张三",96.5);//将 Java 对象转为 JSON 格式resp.setCharacterEncoding("UTF-8");JSONObject jsonObject = JSONObject.fromObject(user);resp.getWriter().write(jsonObject.toString());}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><script type="text/javascript" src="js/jquery-3.3.1.min.js"></script><script type="text/javascript">$(function(){var btn = $("#btn");btn.click(function(){$.ajax({url:'/test',type:'post',dataType:'json',success:function(data){$("#id").val(data.id);$("#name").val(data.name);$("#score").val(data.score);}});});})</script>
</head>
<body>编号:<input id="id" type="text"/><br/>姓名:<input id="name" type="text"/><br/>成绩:<input id="score" type="text"/><br/><input id="btn" type="button" value="提交"/>
</body>
</html>

AJAX的简单应用

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><script type="text/javascript" src="js/jquery-3.3.1.min.js"></script><script type="text/javascript">$(function(){//修改省份$("#province").change(function () {var id = $(this).val();$.ajax({url:"/location",type:"POST",data:"id="+id+"&type=province",dataType:"JSON",success:function(data){var content = "";var cities = data.cities;for(var i=0;i<cities.length;i++){content += "<option>"+cities[i]+"</option>";}$("#city").html(content);content = "";var areas = data.areas;for(var i=0;i<areas.length;i++){content += "<option>"+areas[i]+"</option>";}$("#area").html(content);}});});//修改城市$("#city").change(function(){var id = $(this).val();$.ajax({url:"/location",type:"POST",data:"id="+id+"&type=city",dataType:"JSON",success:function(data){var content = "";for(var i=0;i<data.length;i++){content += "<option>"+data[i]+"</option>";}$("#area").html(content);}});});});</script>
</head>
<body>省:<select id="province"><option value="陕⻄省">陕⻄省</option><option value="河南省">河南省</option><option value="江苏省">江苏省</option></select>市:<select id="city"><option value="⻄安市">⻄安市</option><option value="宝鸡市">宝鸡市</option><option value="渭南市">渭南市</option></select>区:<select id="area"><option>雁塔区</option><option>莲湖区</option><option>新城区</option></select>
</body>
</html>
package com.southwind.entity;
import java.util.List;
public class Location {private List<String> cities;private List<String> areas;public List<String> getCities() {return cities;}public void setCities(List<String> cities) {this.cities = cities;}public List<String> getAreas() {return areas;}public void setAreas(List<String> areas) {this.areas = areas;}
}
package com.southwind.servlet;
import com.southwind.entity.Location;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@WebServlet("/location")
public class LocationServlet extends HttpServlet {private static Map<String, List<String>> cityMap;private static Map<String,List<String>> provinceMap;static {cityMap = new HashMap<>();List<String> areas = new ArrayList<>();//⻄安areas.add("雁塔区");areas.add("莲湖区");areas.add("新城区");cityMap.put("⻄安市",areas);//宝鸡areas = new ArrayList<>();areas.add("陈仓区");areas.add("渭宾区");areas.add("新城区");cityMap.put("宝鸡市",areas);//渭南areas = new ArrayList<>();areas.add("临渭区");areas.add("⾼新区");cityMap.put("渭南市",areas);//郑州areas = new ArrayList<>();areas.add("郑州A区");areas.add("郑州B区");cityMap.put("郑州市",areas);//洛阳areas = new ArrayList<>();areas.add("洛阳A区");areas.add("洛阳B区");cityMap.put("洛阳市",areas);provinceMap = new HashMap<>();List<String> cities = new ArrayList<>();cities.add("⻄安市");cities.add("宝鸡市");cities.add("渭南市");provinceMap.put("陕⻄省",cities);cities = new ArrayList<>();cities.add("郑州市");cities.add("洛阳市");cities.add("开封市");provinceMap.put("河南省",cities);cities = new ArrayList<>();cities.add("南京市");cities.add("苏州市");cities.add("南通市");provinceMap.put("江苏省",cities);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {String type = req.getParameter("type");resp.setCharacterEncoding("UTF-8");String id = req.getParameter("id");switch (type){case "city":List<String> areas = cityMap.get(id);JSONArray jsonArray = JSONArray.fromObject(areas);resp.getWriter().write(jsonArray.toString());break;case "province":List<String> cities = provinceMap.get(id);String city = cities.get(0);List<String> cityAreas = cityMap.get(city);Location location = new Location();location.setCities(cities);location.setAreas(cityAreas);JSONObject jsonObject = JSONObject.fromObject(location);resp.getWriter().write(jsonObject.toString());break;}}
}

JDBC

Java DataBase Connectivity 是⼀个独⽴于特定数据库的管理系统,通⽤的 SQL 数据库存取和操作的公
共接⼝。
定义了⼀组标准,为访问不同数据库提供了统⼀的途径。

JDBC 体系结构

JDBC 接⼝包括两个层⾯:

  • ⾯向应⽤的 API,供程序员调⽤
  • ⾯向数据库的 API,供⼚商开发数据库的驱动程序

JDBC API
提供者:Java 官⽅
内容:供开发者调⽤的接⼝
java.sql 和 javax.sql

  • DriverManager
  • Connection 接⼝
  • Statement 接⼝
  • ResultSet 接⼝

DriverManager
提供者:Java 官⽅
作⽤:管理不同的 JDBC 驱动
JDBC 驱动
提供者:数据库⼚商
作⽤:负责连接不同的数据库

JDBC 的使⽤

1、加载数据库驱动,Java 程序和数据库之间的桥梁。
2、获取 Connection,Java 程序与数据库的⼀次连接。
3、创建 Statement 对象,由 Connection 产⽣,执⾏ SQL 语句。
4、如果需要接收返回值,创建 ResultSet 对象,保存 Statement 执⾏之后所查询到的结果。

package com.southwind.test;
import java.sql.*;
import java.util.Date;
public class Test {public static void main(String[] args) {try {//加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//获取连接String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";String user = "root";String password = "root";Connection connection = DriverManager.getConnection(url,user,password);// String sql = "insert into student(name,score,birthday) values('李四',78,'2019-01-01')";// String sql = "update student set name = '李四'";// String sql = "delete from student";// Statement statement = connection.createStatement();// int result = statement.executeUpdate(sql);String sql = "select * from student";Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql);while (resultSet.next()){Integer id = resultSet.getInt("id");String name = resultSet.getString(2);Double score = resultSet.getDouble(3);Date date = resultSet.getDate(4);System.out.println(id+"-"+name+"-"+score+"-"+date);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e){e.printStackTrace();}}
}

PreparedStatement

Statement 的⼦类,提供了 SQL 占位符的功能
使⽤ Statement 进⾏开发有两个问题:
1、需要频繁拼接 String 字符串,出错率较⾼。
2、存在 SQL 注⼊的⻛险。
SQL 注⼊:利⽤某些系统没有对⽤户输⼊的信息进⾏充分检测,在⽤户输⼊的数据中注⼊⾮法的 SQL
语句,从⽽利⽤系统的 SQL 引擎完成恶意⾏为的做法。

String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url,user,password);
String username = "lisi";
String mypassword = "000";
String sql = "select * from t_user where username = ? and password = ?";
System.out.println(sql);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,username);
preparedStatement.setString(2,mypassword);
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){System.out.println("登录成功");
}else{System.out.println("登录失败");
}
} catch (ClassNotFoundException e) {e.printStackTrace();
} catch (SQLException e){e.printStackTrace();
}

数据库连接池

JDBC 开发流程

  • 加载驱动(只需要加载⼀次)
  • 建⽴数据库连接(Connection)
  • 执⾏ SQL 语句(Statement)
  • ResultSet 接收结果集(查询)
  • 断开连接,释放资源

数据库连接对象是通过 DriverManager 来获取的,每次获取都需要向数据库申请获取连接,验证⽤户
名和密码,执⾏完 SQL 语句后断开连接,这样的⽅式会造成资源的浪费,数据连接资源没有得到很好的重复利⽤。(栗子:就像是你每次打一个电话都要买一个手机,打完一个电话就把手机扔了,很浪费,为什么我们不一直使用第一次买的手机一直打电话呢?)

可以使⽤数据库连接池解决这⼀问题。
数据库连接池的基本思想就是为数据库建⽴⼀个缓冲池,预先向缓冲池中放⼊⼀定数量的连接对象,当需要获取数据库连接的时候,只需要从缓冲池中取出⼀个对象,⽤完之后再放回到缓冲池中,供下⼀次请求使⽤,做到了资源的重复利⽤,允许程序重复使⽤⼀个现有的数据库连接对象,⽽不需要重新创
建。
当数据库连接池中没有空闲的连接时,新的请求就会进⼊等待队列,等待其他线程释放连接。

数据库连接池实现

JDBC 的数据库连接池使⽤ javax.sql.DataSource 接⼝来完成的,DataSource 是 Java 官⽅提供的接
⼝,使⽤的时候开发者并不需要⾃⼰来实现该接⼝,可以使⽤第三⽅的⼯具,C3P0 是⼀个常⽤的第三
⽅实现,实际开发中直接使⽤ C3P0 即可完成数据库连接池的操作。
1、导⼊ jar 包
传统⽅式拿到的 Connection:com.mysql.cj.jdbc.ConnectionImpl@557caf28
C3P0 拿到的 Connection:com.mchange.v2.c3p0.impl.NewProxyConnection@4988d8b8
2、代码实现

package com.southwind.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class DataSourceTest {public static void main(String[] args) {try {//创建C3P0ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8");dataSource.setUser("root");dataSource.setPassword("root");Connection connection = dataSource.getConnection();System.out.println(connection);//还回到数据库连接池中connection.close();} catch (PropertyVetoException e) {e.printStackTrace();} catch (SQLException e){e.printStackTrace();}}
}


实际开发,将 C3P0 的配置信息定义在 xml ⽂件中,Java 程序只需要加载配置⽂件即可完成数据库连接
池的初始化操作。
1、配置⽂件的名字必须是 c3p0-config.xml
2、初始化 ComboPooledDataSource 时,传⼊的参数必须是 c3p0-config.xml 中 named-config 标签的 name 属性值

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config><named-config name="testc3p0"><!-- 指定连接数据源的基本属性 --><property name="user">root</property><property name="password">root</property><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/library?useUnicode=true&amp;characterEncoding=UTF-8</property><!-- 若数据库中连接数不⾜时, ⼀次向数据库服务器申请多少个连接 --><property name="acquireIncrement">5</property><!-- 初始化数据库连接池时连接的数量 --><property name="initialPoolSize">20</property><!-- 数据库连接池中的最⼩的数据库连接数 --><property name="minPoolSize">2</property><!-- 数据库连接池中的最⼤的数据库连接数 --><property name="maxPoolSize">40</property></named-config>
</c3p0-config>
package com.southwind.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class DataSourceTest {public static void main(String[] args) {try {//创建C3P0ComboPooledDataSource dataSource = new ComboPooledDataSource("testc3p0");Connection connection = dataSource.getConnection();System.out.println(connection);//还回到数据库连接池中connection.close();} catch (SQLException e){e.printStackTrace();}}
}

DBUtils

DBUtils 可以帮助开发者完成数据的封装(结果集到 Java 对象的映射)
1、导⼊ jar 包
ResultHandler 接⼝是⽤来处理结果集,可以将查询到的结果集转换成 Java 对象,提供了 4 种实现类。

  • BeanHandler 将结果集映射成 Java 对象 Student
  • BeanListHandler 将结果集映射成 List 集合List <Student >
  • MapHandler 将结果集映射成 Map 对象
  • MapListHandler 将结果集映射成 MapList 结合

【注】:根据返回值决定以上handler。

public static Student findByDBUtils(Integer id){Connection connection = null;Student student = null;try {connection = dataSource.getConnection();String sql = "select * from student";//String sql = "select * from student where id=?";QueryRunner queryRunner = new QueryRunner();List<Map<String,Object>> list = queryRunner.query(connection,sql,new MapListHandler());//List<Map<String,Object>> list = queryRunner.query(connection,sql,new BeanHandler<>(Student.class),id);for (Map<String,Object> map:list){System.out.println(map);}} catch (SQLException e) {e.printStackTrace();} finally {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}return student;
}


【代码来源】参考楠哥教学视频:https://www.bilibili.com/video/BV1BJ411L7NR
【JavaWeb实战代码及所需jar包】:https://download.csdn.net/download/hhhmonkey/21516713

JavaWeb基础学习笔记相关推荐

  1. [硬核]卷起来!两万六千字总结的JavaWeb核心技术学习笔记

    文章目录 前言 http协议笔记 JavaWEB笔记_1 JavaWEB笔记_2(JSP) JavaWEB笔记_3(web项目) Servlet Tomcat笔记 总结 前言 大家好,我是ChinaM ...

  2. guido正式发布python年份_Python 基础学习笔记.docx

    Python 基础学习笔记 基于<Python语言程序设计基础(第2版)> 第一部分 初识Python语言 第1章 程序设计基本方法 1.1 计算机的概念 计算机是根据指令操作数据的设备, ...

  3. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

  4. Python3 基础学习笔记 C09【文件和异常】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  5. Python3 基础学习笔记 C08 【类】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  6. Python3 基础学习笔记 C07【函数】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  7. Python3 基础学习笔记 C06【用户输入和 while 循环】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  8. Python3 基础学习笔记 C05【字典】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  9. Python3 基础学习笔记 C04【if 语句】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

最新文章

  1. Ubuntu12.04安装Mac OSX Yosemite
  2. 联想g510拆键盘的简单方法_如何拆室内门锁?有方法太简单了
  3. 基础篇-verilog-按位与和逻辑与
  4. 应云而生,幽灵的威胁 - 云原生应用交付与运维的思考
  5. PyQt、QtDesigner及其它工具包的安装
  6. webpack-dev-server启动后,localhost:8080返回index.html的原理
  7. 实训项目四 powerpoint 综合应用_【深化改革结硕果】新疆番茄综合精深加工关键技术及产业化应用项目取得重大突破...
  8. linux脚本调用job,linux shell - 脚本中调用fg调取后台任务报错
  9. Windows自带利器:Rundll.exe高级应用
  10. GrADS读取.grb2文件记录
  11. t分布 u分布 卡方分布_几种分布概述(正态分布/卡方分布/F分布/T分布)
  12. 3D 旋转立方体的完整代码
  13. 最小外接矩形--最大内接矩形
  14. 何同学采访苹果CEO库克上热搜,网友表示自愧不如
  15. python使用matplotlib绘制3D图
  16. 一文说透企业风险管理的三大要素分别是什么
  17. JMeter 性能测试实例
  18. 计算机底层:海明校验码。
  19. 镜像电流源特点_镜像电流源原理及其应用电路.pdf
  20. 2020-12-10 MATLAB学习小结(十九)

热门文章

  1. Codeup墓地-问题 A: 还是畅通工程
  2. 微博环境下利用综合策略构建推荐引擎
  3. hdu 1569 方格取数(2) 最大点权独立集
  4. 避坑_node-sass安装问题及解决办法
  5. 【双100%解法】剑指 Offer 24. 反转链表
  6. 【最新合集】编译原理习题(含答案)_1 绪论_MOOC慕课 哈工大陈鄞
  7. Azkaban报错:Missing required property ‘azkaban.native.lib’
  8. 树莓派更换软件源提高下载速度
  9. mongo mapreduce java_那位帮忙提供一个java mongodb多个collection进行mapreduce的操作。
  10. mysql拒绝访问root用户_设置mysql的root用户允许远程登录