创建java web项目
idea+tomcat7
新建web项目
目录结构如下
配置tomcat
运行,并通过浏览器访问
Servlet
什么是servlet
servlet 是java web 开发的基石,它是运行在servlet容器中(tomcat)中,负责与客户端进行通信。
-
servlet功能:
- 创建 并返回基于客户端请求的动态html页面。
- 与数据库进行通信
-
Servlet 使用
Servlet本身是一组接口,自定义一个类,实现servlet接口,这个类就具备了接收客户端请求以及相应的功能
浏览器不能直接访问Servlet文件,只能通过映射的方式来间接访问servlet,映射需要开发者手动配置,有两种配置方式 -
配置web.xml,将url地址与servlet进行映射:
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>com.youzm.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
- 基于注解的方式:
启动调用
Servlet生命周期
- 当浏览器访问SErvlet的时候,tomcat会查询当前SErvlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象
- 调用init方法完成初始化操作
- 调用service方法完成业务逻辑操作
- 关闭tomcat时,会调用destory方法,释放当前对象所占用资源
Servlet的生命周期方法,无参构造方法,init,service,destory
1、无参构造函数只调次,创建对象。
2、init 只调用1次,初始化对象。
3、service 调用 N 次,执行业务方法。
4、destory 只调一次,卸载对象。
Servlet的层次结构
Servlet–》GenericServlet–》HttpServlet
在servlet中,与业务相关且使用最多的方法为service方法,所以tomcat中为我们提供了GenericServlet和HttpServlet方法,他们都分别实现了servlet和继承GenericServlet,我们只需要编写自己的类并继承HttpServlet方法,并重写其doGet,doPost等方法。
@WebServlet("/httpdemo1")
public class HttpServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Get");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Post");
}
}
JSP
jsp本质是一个servlet,主要负责与用户交互,将最终的页面呈现给用户,html+js+css+java混合文件
当服务器接收到一个后缀是jsp的请求是,将该请求交给jsp引擎去处理,每一个jsp页面第一次被访问的时候会翻译成一个servlet文件,再有web容器调用servlet完成响应
单纯看:jsp就是html中嵌入java程序
具体嵌入方式额三种:
- jsp脚本,执行java逻辑代码
<% java 代码 %>
- jsp声明,定义Java方法
<%! 声明java方法%>
- jsp 表达式
<%= java 变量%>
示例:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<$END$
<body>
<h1>第一个java web程序</h1>
<%!
public String test(){
return "Hello world";
}
%>
<%
String str=test();
%>
<%=
str
%>
</body>
</html>
JSP内置对象9个
- request:表示一次请求,HttpServletRequest
- response:表示一次响应,HttpServletResponse
- pageContext:页面上下文,获取页面信息,PageContext
- session:表示一次会话,保存用户信息,HttpSession
- application:表示当前web引用,全局对象,保存所有用户共享信息,ServletContext
- config:当前jsp对应的servlet的servletConfig对象,获取当前servlet信息
- out:向浏览器输出数据,jspWriter
- page: :当前jsp对应的servlet对象,Servlet
- exception:表示jsp页面发生的异常,Exception
常用的是request,response,session,application,pageContext
request常用方法
- String getParameter(String key):用来获取客户端传递的参数(key-value) ;
- void setAttribute(String key,Object value):通过键值对的形式保存数据;(服务端内部之间传递
- Object getAttribute(String key): 通过key获取value
- RequestDispatcher getRequestDispatcher(String path):返回一个RequestDispatch对象,该对象的forward方法用于请求转发
- String[] getParameterValues():获取客户端传来的多个同名参数;
- void setCharacterEncoding(String charset):指定每个请求的编码;
response常用方法
- sendRedirect(String path):重定向地址,页面之间的跳转;
转发getRequestDispatcher和重定向sendRedirect的区别:
- 转发是将同一个请求传给下一个页面,重定向是创建一个新请求传给下一个页面,之前的请求结束生命周期;
- 转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转;
- 重定向:由客户端发送一次新的请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转;
** 如果两个页面之间需要通过request来传值,则必须使用转发,不能使用重定向**
Session
用户会话
服务器无法识别每一次Http请求的出处,他只会接收到一个请求信号,所以就存在一个问题:将用户的响应发送给其他人,必须有一种技术来让服务器知道请求来自哪,这就是会话技术;
会话:就是客户端和服务端之间发生的一系列连续的请求响应的过程,–》打开浏览器操作到关闭浏览器的过程;
会话状态:值服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同义词绘画的一系列请求和响应关联起来;
实现会话的两种方式:
- cookie
- session
session:属于同一次会话的请求都会有一个相同的标识符(sessionId)
session 常用的方法:
String getId(): 获取当前sessionId
void setMaxInactiveInterval(int interval) 设置当前session失效时间,单位为s
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 coolie=new Cookie("name","zhangsan");
response.addCookie(cookie);
- 读取
Cookie[] cookies=request.getCookies();
for(Cookie c:cookies){
out.write(c.getName()+":"+c.getValue());
}
常用方法:
void setMaxAge(int age):设置Cookie的有效时间,单位s;销毁时设置为0;
int getMaxAge():获取cookie有效时间
String getName()获取Cookie的name
String getValue()获取Cookie的value
Session和Cookie的区别
session 保存在服务器
保存的数据类型为Object
随会话结束销毁
保存重要信息
cookie 保存在客户端
保存的数据类型为String
可长期保存,与会话无关
保存不重要信息
jsp内置对象的作用域
4个:
page,request,session,application
这四个有setAttribute和getAttribute方法存储数据,区别为范围不一样;
- page作用域:对应的内置对象为pageContext,当前页面有效
- request作用域:对应的内置对象是request,再一次请求内有效
- session作用域:对应的内置对象是seesion,在一次会话有效
- application作用域:对应的内置对象是application,对应蒸锅web应用。
page<reqeust<session<application
EL表达式
Expression Language表达式语言,代替jsp页面中数据访问时的复杂编码,可以非常便捷的取出域对象(page,request,session,application)中保存的数据,前提是一定要先setAttribute。
$(表达式)
变量名是setAttribute对应的key值
EL对于4种域对象的查找顺序:
pageContext==》request==》session==》application
按照上述的顺序进行查找,找到立即返回,若没找到,则返回null;
也可以指定作用域查找
${requestScope.name}:在request中查找name
EL执行表达式
&& || ! < > <= >= ==
主要用来取数据
JSTL
jsp Standard Tag Library :jsp标准标签库,jsp为开发者提供了一系列的标签,使用这些标签可以完成一些逻辑处理,比如循环遍历集合,让代码更加简洁,不在出现jsp脚本穿插的情况
实际开发中EL和jstl结合使用,JSTL侧重于逻辑处理,EL负责数据展示
JSTL的是使用:
- 需要导入jar包
jstl.jar
,standard.jar
- 在jsp页面开始的地方引入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
- 在需要的地方使用
<c:forEach items="${list}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.adderss.value}</td>
</tr>
</c:forEach>
JSTL优点:
- 提供了统一的标签
- 可以用于编写各种动态功能吧
常用标签:
set out remove catch
set:向域对象中添加数据
向requst域中添加key为name,value为tom的数据
<c:set var="name" value="tom" scope="request"></c:set>
过滤器
Filter
功能:
- 用来拦截传入的请求和传出的响应。
- 修改或以某种方式正在客户端和服务端之间交换的数据流
如何使用:
与使用servlet类似,Filter是java web提供的一个接口,开发者只需要自定义一个类并且实现该接口即可;
public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
web.xml中配置Filter
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>com.youzm.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter生命周期
当Tomcat启动时,通过反射机制调用Filter的无参构造函数创建实例化对象,同时调用init方法实现初始化,doFilter方法调用很多次,当tomcat关闭时,调用destory来销毁Filter对象。
- 无参构造函数:只调用一次,当Tomcat启动时,(filter一定要进行配置(xml,注解@WebFilter))
- init方法:只调用一次,当Filter实例化对象创建完成之后调用
- doFilter:调用多次,访问Filter业务时调用
- destory:关闭服务时调用
同时配置多个Filter,调用顺序是由web.xml中的配置顺序来决定。从上往下顺序读取;
实际开发中Filter的使用场景:
- 同一处理中文乱码;
- 屏蔽敏感词;
- 控制资源的访问权限;
文件上传下载
上传
- jsp
- input的type设置为file
- form表单的method设置为post,get方式只会传入文件名
- form表单的enctype设置为multipart/form-data,以二进制的形式传输数据
- servlet
使用fileUpload组件,可以将所有的请求信息解析成FileIteam对象,可以沟通过对FileItem对象的操作完成上传,面向对象的思想
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem> list = servletFileUpload.parseRequest(req);
使用示例:
jsp:
<form enctype="multipart/form-data" action="/upload" method="post">
<input type="file" name="img">
<input type="submit" value="上传">
</form>
servlet
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem> list = servletFileUpload.parseRequest(req);
System.out.println(list);
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);
InputStream inputStream=fileItem.getInputStream();
String path=req.getServletContext().getRealPath("file/"+fileName);
OutputStream outputStream=new FileOutputStream(path);
int temp=0;
while ((temp=inputStream.read())!=-1){
outputStream.write(temp);
}
outputStream.close();
inputStream.close();
System.out.println("上传成功");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
下载
get方式下载
jsp
<a href="/download" >1.png</a>
servlet
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String filename="1.png";
//设置响应方式
resp.setContentType("application/x-msdownload");
//设置下载后的文件名
resp.setHeader("Content-Disposition","attachment;filename="+filename);
//获取输出流
OutputStream outputStream=resp.getOutputStream();
String path=req.getServletContext().getRealPath("file/1.png");
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 不是新的编程,指的是一种交互方式,异步加载,客户端和服务器的数据交互更新在局部页面的
技术,不需要刷新整个页面(局部刷新)
优点:
- 局部刷新,效率更高
- 用户体验更好
基于jquery的ajax
使用示例:
<script type="text/javascript">
$(function () {
var btn=$("#btn");
btn.click(function () {
$.ajax({
url:"/ajax",
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>
servlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String id=(String)req.getParameter("id");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str="Hello world";
resp.getWriter().write(str);
}
传统的web数据交互与ajax数据交互的区别
- 客户端请求的方式不一样:
- 传统:浏览器发送同步请求(form表单,a标签)
- ajax:异步引擎对象发送异步请求 - 服务器响应方式不同:
- 传统:响应一个完整的jsp页面(视图)
- ajax:响应需要的数据 - 客户端处理方式不同
- 传统:需要等待服务器完成响应并且重新加载整个页面之后,用户才能进行后续的操作
- ajax:动态更新页面中的局部信息,不影响用户的其他操作
基于jQuery的ajax的语法
$.ajax({属性})
常用的属性参数:
url:请求的后端服务地址
type:请求方式,默认get
data:请求参数
dataType:服务器返回的数据类型,text/json
success:请求成功的回调函数
error:请求失败的回调函数
complete:请求完成的会调函数(无论成功或失败,都会调用)
JDBC
java dataBase Connectivity java数据库连接技术,独立于特定数据库的管理系统,提供了通用的 sql数据库存取和操作的公共接口
定义了一组接口,为访问数据库提供了统一途径
JDBC API
提供者:java官方
内容:供开发者调用的接口
java.sql和javax.sql
- DriverManager类
- Connerction接口
- Statement接口
- ResultSet接口
DriverManager
提供者:java官方
作用:管理不同的jdbc驱动
jdbc驱动
提供者:数据库厂商
作用:负责连接不同数据库
使用
- 加载数据库驱动,java程序和数据库之间的桥梁
- 获取Connection,java程序与数据库的一次连接
- 创建Statement对象,有connection产生,执行sql语句
- 如果需要接受返回值,创建ResultSet对象,保存Statement执行之后所查询到的结果
public static void main(String[] args) {
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url="jdbc:mysql://localhost:3306/sql?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String user="root";
String password="root";
Connection connection= DriverManager.getConnection(url,user,password);
// System.out.println(connection);
// String sql="insert into student(name,score,birthday) values ('李四',78,'2020-12-23')";
// String sql="update student set name='李四'";
// String sql="delete from student";
// Statement statement=connection.createStatement();
// int result=statement.executeUpdate(sql);
// System.out.println(result);
String sql="select * from student";
Statement statement=connection.createStatement();
ResultSet resultSet=statement.executeQuery(sql);
while (resultSet.next()){
Integer id=resultSet.getInt(1);
String name=resultSet.getString("name");
Integer score=resultSet.getInt(3);
Date date=resultSet.getDate(4);
System.out.println(id+"-"+name+"-"+score+"-"+date);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
PreparedStatement
Statement子类,提供占位符
示例:登录功能:
使用前:
public static void main(String[] args) {
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/sql?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);
String username = "lisi";
String mypassword = "000";
String sql = "select * from user where name='" + username + "' and password= '" + mypassword+"'";
System.out.println(sql);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
使用Statement进行开发有两个问题
- 需要频繁拼接String字符串,出错率高
- 存在sql注入风险
sql注入:利用某些系统没有对用户输入的信息进行充分检测,在用户输入的数据中心注入非法的sql语句,从而利用系统的dql引擎完成恶意行为的做法
String username = "lisi";
String mypassword = "000";
String sql="select * from user where name=? and password=?";
PreparedStatement preparedStatement=connection.prepareStatement(sql);
preparedStatement.setString(1,username);
preparedStatement.setString(2,mypassword);
ResultSet resultSet=preparedStatement.executeQuery();
数据库连接池
JDBC开发流程
- 加载驱动(只需要加载一次)
- 建立数据库连接(Connection)
- 执行sql语句(Statement)
- Resultset接收结果(查询)
- 断开连接,释放资源
数据库连接对象是通过DriverManager来获取,每次获取都需要向数据库申请获取连接,验证用户名密码,执行完sql后断开连接,这样的方式会造成资源的浪费,数据连接资源没有得到很多复用。
可以使用数据库连接池解决这一问题。
数据库连接池的基本思想是为数据库建立一个缓冲池,预先向缓冲池中放入一定数量的连接对象,当获取数据库连接时,只需要从缓冲翅中取出一个对象,用完之后再放回缓冲池中,供下次使用,做到了资源的复用,允许程序重复使用一个现有的数据库连接对象,而不是重新创建连接。
数据库连接池的实现
jdbc的数据库连接池使用javax.sql.DataSource接口来实现的,DataSource是java官方提供的接口,使用时开发者不需要来实现该接口,可以使用第三方工具,C3P0是一个常用的第三方实现,实际开发中直接使用c3p0即可完成数据库连接池的操作。
- 导入jar包
c3p0-0.9.5.5.jar
和mchange-commons-java-0.2.19.jar
- 代码实现
public static void main(String[] args) {
try {
//创建c3p0
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/sql?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
dataSource.setUser("root");
dataSource.setPassword("root");
//设置初始化连接个数
dataSource.setInitialPoolSize(5);
//设置最小
dataSource.setMinPoolSize(2);
//当连接对象不够,再次申请连接个数
dataSource.setAcquireIncrement(5);
//设置最大连接个数
dataSource.setMaxPoolSize(20);
Connection connection=dataSource.getConnection();
/*
* 执行sql
* */
System.out.println(connection);
connection.close();
} catch (PropertyVetoException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
实际开发中使用xml方式进行配置,修改不需要再次编译
xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="c3p0">
<!-- 指定连接数据源的基本属性 -->
<property name="user">root</property>
<property name="password">root</property>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/sql?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC</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>
java代码
public static void main(String[] args) {
try {
ComboPooledDataSource dataSource=new ComboPooledDataSource("c3p0");
Connection connection=dataSource.getConnection();
/*
* 执行sql
* */
System.out.println(connection);
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
DBUtils
DBUtils 可以帮助开发者完成数据的封装(结果集到 Java 对象的映射)
-
导入jar包
mysql-connector-java-8.0.20.jar
-
ResultHandler 接口是用来处理结果集,可以将查询到的结果集转换成 Java 对象,提供了 4 种实现类。
- BeanHandler 将结果集映射成 Java 对象 Student
- BeanListHandler 将结果集映射成 List 集合 List
- MapHandler 将结果集映射成 Map 对象
- MapListHandler 将结果集映射成 MapList 结合
示例:
try {
ComboPooledDataSource dataSource=new ComboPooledDataSource("c3p0");
Connection connection=dataSource.getConnection();
String sql="select * from student where id=1";
QueryRunner queryRunner=new QueryRunner();
Student student=queryRunner.query(connection,sql,new BeanHandler<>(Student.class));
System.out.println(student);
System.out.println(connection);
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
参考视频:
B站楠哥----java web从入门到实战