一.tomcat
简介: tomcat 是 免费的web服务器
1. 常见目录:
lib tomcat的类库
bin tomcat的启动和关闭 (startup.bat启动,shutdown.bat 关闭)启动后浏览器:
输入htpp://http://localhost:8080 ,出现tocmat图片即说明安装成功
conf 配置文件目录
webapps 存放web项目的目录,在浏览器地址栏不可见
work jsp 相关目录 已不使用
2:webapp标准结构:
app
--static
--page
--WEB-INF
classes
lib
web.xml
app:本应用根目录
static 非必要目录,约定俗成的名称,一般在此放静态资源(css js img)
page: 非必要目录,一般存放html文档
WEB-INF 必要目录,必须叫WEB-INF,受保护的资源目录,浏览器通过url 不可以直接访问的目录
WEB-INF 目录下的三个部分:
classes 字节码根路径
lib 依赖的存放路径
web.xml 项目的配置文件
3.web项目的部署方式:
方式一:直接将编译好的项目放在webapps目录下
方式二: 将编译好的项目打成war包放在webapps目录下,tomcat启动后 自动解压war包(和第一种一样)
方式三:可以将项目放在非webapps的其他目录,在tomcat中通过配置文件指向app的实际磁盘路径
idea关联tomcat
File 目录 选择 setttings
build,Execution,Deployment 选择 Applicaiton Servers
选择右侧的+ 选择tomcat server,选择tomcat的路径即可
4.idea开发web工程并部署
新建一个webwokrspace 并使用idea打开
新建一个module,输入名称并保存
选中module 选择project Structure
选中工程 在Dependencies 中点击+ 增加tomcat
选中新建的module 右键 选择 Add Framework Support 在javaEE下勾选 web Application,点击确定 工程变成web工程
在 运行左边的tomcat 下拉选择 edit configuration
切换到Deployment
选择工程 部署
Application context :配置的为浏览器工程访问路径
点击确定 即可
二:http
1.简介:
超文本传输协议,是一个属于应用层面向对象的协议,它是一种详细规定了浏览器
和万维网服务器之间相互通信的规则,通过网络传送万维网文档的数据传送协议,客户端与服务端通信时
传输的内容称为报文,http协议就是规定报文的格式。
客户端发送给服务器的称为请求报文,服务器发送给客户端的称为响应报文
交互方式
请求 永远都是客户端向服务端发送
响应 永远都是服务器向客户端返回
数据格式
请求时发送的数据称为请求报文
响应时返回的数据称为响应报文
报文是有规定的格式
报文首部 请求报文 响应报文
行 请求行 响应行
头 请求头 响应头
报文主体 请求体 响应体
2.请求和响应报文
请求报文格式
请求首行:get/post 资源路径?参数 HTTP/1.10
请求头信息(请求头)
空行
请求体:post请求才有请求体
响应报文格式
响应行
响应头
响应体
3.常见响应码
200 请求成功,浏览器会把响应内容(通常时html)显示在浏览器中
302 重定向 表示服务器要求浏览器重新在发一个请求,服务器会发送一个响应头location指定新请求的URL地址
304 使用了本地缓存
404 请求的资源没有找到,说明客户端错误的请求了不存在的资源;
405 请求的方式不允许
500:请求资源找到了,但是服务器内部出现了错误
4.url与项目资源的对应关系
三 :servlet
1.简介:
运行在服务器端(tomcat)的java 小程序,是sun公司提供一套定义动态资源规范,从代码
层面上讲servlet就是一个接口
--
用来接收/处理客户端请求,响应给浏览器的动态资源,在整个web应用中,servlet主要
负责接收处理请求,协同调度功能以及响应数据。我们把Servlet称为web应用中的控制器
2.servlet开发流程
1.创建JAVAWEB项目,同时将tomcat添加为当前项目的依赖
2.重写service方法,service(HttpServlet req,HttpServletResponse resp)
3.在service方法中 ,定义业务处理代码
4.在web.xml中 ,配置servlet 对应的请求映射路径
<servlet>
<servlet-name>userservlet</servlet-name>
<servlet-class>com.cn.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userservlet</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>
url-pattern 特殊配置
/ 表示通配所有资源,不包括jsp文件
/* 表示通配所有资源,包括jsp文件
/a/* 匹配 所有以a前缀的映射路径
*.action 匹配所有以action为后缀的映射路径
注解配置servlet
在具体的servlet 类加注解
三种写法
@WebServlet("/s1")
@WebServlet("value=/s1")
@WebServlet("UrlPatterns=/s1")
3.servlet 生命周期
生命周期 对应方法 执行时机 执行次数
构造对象 构造器 第一次请求或者容器启动 1
初始化 init() 构造完毕后 1
处理服务 service(HttpServletRequest 每次请求 多次
req,HttpServletResponse resp)
销毁 destory() 容器关闭 1
Servlet 在Tomcat 中是单例的
Servlet 的成员变量在多个线程栈之间共享
不建议 在service 方法中修改成员变量,在并发请求时,会引发线程安全问题
default-servlet 用于加载静态资源的servlet,默认随服务启动,默认启动序号为1
4.servlet 继承结构
1.顶级的Servlet接口
public interface Servlet {
//初始化方法,构造完毕后,由tomcat自动调用完成初始化功能的方法
void init(ServletConfig var1) throws ServletException;
//获得ServletConfig对象的方法
ServletConfig getServletConfig();
//接收用户请求,向用于响应信息的方法
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
//返回Servlet字符串形式描述信息的方法
String getServletInfo();
// Servlet在回收前,由tomcat调用的销毁方法,往往用于做资源的释放工作
void destroy();
2.抽象的类 GenericServlet
public abstract class GenericServlet implements Servlet {
private transient ServletConfig config;
//将抽象方法改为普通方法,在方法内部没有任何的实现代码
public void destroy() {
}
public String getInitParameter(String name) {
return this.getServletConfig().getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
return this.getServletConfig().getInitParameterNames();
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
public String getServletInfo() {
return "";
}
//tomcat 在调用Init方法时,会读取配置信息进入一个ServletConfig对象,并将该对象传入init方法
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
//重载的初始化方法,我们重写初始化方法时对应的方法
public void init() throws ServletException {
}
//再次抽象声明Service方法
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
return this.config.getServletName();
}
}
3.抽象类的 HttpServlet侧重Service方法的处理
public abstract class HttpServlet extends GenericServlet
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
this.service(request, response);
}
5.servletConfig
web.xml 初始化配置信息
<servlet>
<servlet-name>servletconfig</servlet-name>
<servlet-class>com.cn.ServletConfigDemo</servlet-class>
<init-param>
<param-name>keya</param-name>
<param-value>valuea</param-value>
</init-param>
<init-param>
<param-name>keyb</param-name>
<param-value>valueb</param-value>
</init-param>
</servlet>
//获取ServletConfig对象
ServletConfig servletConfig = getServletConfig();
//获取指定初始化属性值
String keya = servletConfig.getInitParameter("keya");
System.out.println("keya="+keya);
//获取所有初始化属性
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String nextElement = initParameterNames.nextElement();
System.out.println(nextElement);
}
6.servletContext
web.xml 初始化配置信息
<context-param>
<param-name>con1</param-name>
<param-value>vaule1</param-value>
</context-param>
<context-param>
<param-name>con2</param-name>
<param-value>vaule2</param-value>
</context-param>
//获取servletContext对象
ServletContext servletContext1 = getServletContext();
ServletConfig servletConfig = getServletConfig();
ServletContext servletContext2 = servletConfig.getServletContext();
ServletContext servletContext3 = req.getServletContext();
//域对象只有一个,可以在多个Servlet之间共享属性
System.out.println(servletContext1==servletContext2);
System.out.println(servletContext3==servletContext2);
//获取servletContext初始属性和属性值
String con1 = servletContext1.getInitParameter("con1");
System.out.println(con1);
Enumeration<String> initParameterNames = servletContext1.getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String element = initParameterNames.nextElement();
System.out.println(element+"="+servletContext1.getInitParameter(element));
}
// 域对象 设置属性
servletContext1.setAttribute("ka","va");
// 域对象 获取属性
String ka = (String) servletContext1.getAttribute("ka");
System.out.println(ka);
//域对象修改属性
servletContext1.setAttribute("ka","vaa");
// 域对象 获取属性
String ka = (String) servletContext1.getAttribute("ka");
System.out.println(ka);
//域对象 删除属性
servletContext1.removeAttribute("ka");
7.HttpServletRequest
HttpServletRequest 是一个接口,其父接口是ServletRequest
HttpServletRequest 是tomcat 将请求报文转换封装而来的对象,在tomcat调用service方法时传入
HttpServletRequest 代表客户端发来的请求,所有请求中的信息可以通过该对象获得
//获取方法
String method = req.getMethod();
System.out.println(method);
//获取协议
String protocol = req.getProtocol();
System.out.println(protocol);
//获取资源路径
String requestURI = req.getRequestURI();
System.out.println(requestURI);
//获取资源完整路径
StringBuffer requestURL = req.getRequestURL();
System.out.println(requestURL);
//客户端发送请求使用的端口号,有可能时代理的
int serverPort = req.getServerPort();
System.out.println(serverPort);
//本应用容器端口号
int localPort = req.getLocalPort();
System.out.println(localPort);
//获取指定请求头信息
String accpet = req.getHeader("Accpet");
System.out.println(accpet);
//获取所有请求头信息
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String element = headerNames.nextElement();
System.out.println(element+":"+req.getHeader(element));
}
//获取指定属性值
String username = req.getParameter("username");
System.out.println("username="+username);
String password = req.getParameter("password");
System.out.println("pasword="+password);
//获取参数的多个值
String[] hobbies = req.getParameterValues("hobby");
System.out.println("hobby:"+Arrays.toString(hobbies));
//获取所有参数
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()){
String element = parameterNames.nextElement();
String[] parameterValues = req.getParameterValues(element);
if(parameterValues.length>1){
System.out.println(element+"="+Arrays.toString(parameterValues));
}else{
System.out.println(element+"="+parameterValues[0]);
}
}
//获取属性map集合,key=属性,value=属性值
Map<String, String[]> parameterMap = req.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
String[] value = entry.getValue();
if(value.length>1){
System.out.println(key+"="+Arrays.toString(value));
}else{
System.out.println(key+"="+value[0]);
}
}
//设置响应码
resp.setStatus(201);
//设置响应内容
resp.setContentType("text/html");
//设置影响内容
String info="hello";
PrintWriter writer = resp.getWriter();
writer.write(info);
8.请求转发和重定向
请求转发:
请求转发通过HttpServletRequest对象获取请求转发器实现
请求转发是服务器内部的行为,对客户端是屏蔽的
客户端只发送了一次请求,客户端地址栏不变
服务端只产生了一对请求和响应对象,这一对请求和响应会继续传递给下一个资源
因为全程只有一个HttpServletRequest对象,所以请求参数可以传递,请求域中的数据也可以传递
请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转
请求转发可以转发给WEB-INF下受保护的资源,该方式也是WEB—INF下的资源的唯一访问方式
实现:
//获取转发器
// RequestDispatcher dispatcher = req.getRequestDispatcher("servletB");
// RequestDispatcher dispatcher = req.getRequestDispatcher("a.html");
// RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/b.html");
RequestDispatcher dispatcher = req.getRequestDispatcher("h'ttp://www.qq.com");
//转发器发送
dispatcher.forward(req,resp);
重定向:
响应重定向通过HttpServletResponse对象的sendRedirect方法实现
响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的客户端行为
客户端至少发送了两次请求,客户端地址栏是要变化的
服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源
因为全程产生了多个HttpServletRequest对象,所以请求参数不可以传递,请求域中的数据也不可以传递
重定向可以是其他serlvet动态资源,也可以是一些静态资源以实现页面跳转
重定向不可以访问到WEB_INF下受保护的资源
实现:
//响应重定向 设置响应状态码为302,同时设置location响应头为servlet2
// resp.sendRedirect("servlet2");
// resp.sendRedirect("a.html");
// resp.sendRedirect("WEB-INf/b.html");
resp.sendRedirect("http://www.baidu.com");
总结:同样能够实现页面跳转,优先使用响应重定向
9.web访问图解:
四:实例: 实现用户注册和用户登录的前后台交互
工程结构:
Model层代码:
service与实现类
public interface SysUserService { /** 服务层 定义实现用户注册的功能 para:用户对象 return:返回影响的行数 */ int register(SysUser user); /** 服务层 定义实现用户登录的功能 para:用户名 return:返回影响的行数 */ SysUser login(String username) throws Exception; }
public class SysUserServiceImpl implements SysUserService { private SysUserDao userdao=new SysUserDaoImpl(); @Override public int register(SysUser user) { return userdao.addUser(user); } @Override public SysUser login(String username) throws Exception { return userdao.findByName(username); } }
dao层
数据库操作的相关类:
public class BaseDao { //返回单个对象 public <T> T baseQueryObject(Class<T> clazz, String sql, Object... args) throws SQLException { T t = null; Connection connection = JDBCUtil.getConnection(); ResultSet resultSet = null; try { PreparedStatement preparedStatement = connection.prepareStatement(sql); int rows = 0; for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { t = (T) resultSet.getObject(1); } } catch (SQLException e) { throw new RuntimeException(e); } finally { if (null != resultSet) { resultSet.close(); } } return t; } //返回多个对象集合 public <T> List<T> baseQuery(Class<T> clazz, String sql, Object... args) throws Exception { T t = null; Connection connection = JDBCUtil.getConnection(); List<T> list = new ArrayList<>(); ResultSet resultSet = null; try { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); while (resultSet.next()) { Object obj = clazz.newInstance(); for (int i = 1; i <= columnCount; i++) { String columnname = metaData.getColumnLabel(i); Object value = resultSet.getObject(columnname); if (value.getClass().equals(LocalDateTime.class)) { value = Timestamp.valueOf((LocalDateTime) value); } Field field = clazz.getDeclaredField(columnname); field.setAccessible(true); field.set(obj, value); } list.add((T) obj); } if (resultSet.next()) { t = (T) resultSet.getObject(1); } } catch (SQLException e) { throw new RuntimeException(e); } finally { if (null != resultSet) { resultSet.close(); } } return list; } //普通的增删改方法 public int baseUpdate(String sql, Object... args) throws Exception { Connection connection = JDBCUtil.getConnection(); int rows = 0; try { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } rows = preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if (null != connection) { connection.close(); } } return rows; } }
public class SysUserDaoImpl extends BaseDao implements SysUserDao { @Override public int addUser(SysUser user) { String sql ="insert into sys_user values(DEFAULT,?,?)"; try { return baseUpdate(sql, user.getUsername(), user.getUserPwd()); } catch (Exception e) { throw new RuntimeException(e); } } @Override public SysUser findByName(String username) throws Exception { String sql="select uid,username,password userPwd from sys_user where username=?"; List<SysUser> sysUsers = baseQuery(SysUser.class, sql, username); return (sysUsers==null&&sysUsers.size()==0)?null:sysUsers.get(0); } }
数据库连接工具类:
public class JDBCUtil { private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>(); private static DataSource dataSource; //初始化连接池 static { Properties properties =new Properties(); InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); try { properties.load(resourceAsStream); } catch (IOException e) { throw new RuntimeException(e); } try { dataSource = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { throw new RuntimeException(e); } } public static DataSource getDateSource(){ return dataSource; } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }
控制层代码:
public class BaseController extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); String[] splits = requestURI.split("/"); String mehodname = splits[splits.length - 1]; Class aClass = this.getClass(); try { //通过反射获取方法名,并执行方法 Method declaredMethod = aClass.getDeclaredMethod(mehodname, HttpServletRequest.class, HttpServletResponse.class); declaredMethod.invoke(this, req, resp); } catch (Exception e) { throw new RuntimeException(e); } } }
@WebServlet("/sysuser/*") public class SysUserController extends BaseController { private SysUserService userservice = new SysUserServiceImpl(); protected void register(HttpServletRequest req, HttpServletResponse resp) throws Exception { //1.获取请求信息 String username = req.getParameter("username"); String password = req.getParameter("userpwd"); //封装请求信息 SysUser user = new SysUser(); user.setUsername(username); user.setUserPwd(password); //调用服务层处理请求 int register = userservice.register(user); //返回跳转信息 if(register>0){ resp.sendRedirect("/registersucess.html"); }else{ resp.sendRedirect("/registererror.html"); } } protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1获取请求参数 String username = req.getParameter("username"); String userPwd = req.getParameter("pwd"); //调用服务层处理 SysUser sysuer= null; try { sysuer = userservice.login(username); } catch (Exception e) { e.printStackTrace(); }//返回跳转信息 if(null==sysuer){ resp.sendRedirect("/loginusernameerror.html"); }else if( !userPwd.equals(sysuer.getUserPwd())){ resp.sendRedirect("/loginpassworderror.html"); }else{ resp.sendRedirect("/loginsucess.html"); } } }
视图层代码:
login.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> span{ font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; color: red; } </style> <script> //校验用户名 function checkusername(){ var reg=/^[a-zA-Z0-9]{6,10}$/ var usernameobj= document.getElementById("user1") var uservalue=usernameobj.value var usercheck=reg.test(uservalue) var sp1= document.getElementById("sp1") if(!usercheck){ sp1.innerText="用户名格式不正确" return false } sp1.innerText="OK" return true } //校验密码 function checkpassword(){ var reg=/^\d{6}$/ var pwdobj= document.getElementById("pw1") var pwdvalue=pwdobj.value var pwdcheck=reg.test(pwdvalue) var sp2= document.getElementById("sp2") if(!pwdcheck){ sp2.innerText="密码格式不正确" return false } sp2.innerText="OK" return true } function checksubmit(){ var flag1=checkpassword() var flag2=checkpassword() return flag1&&flag2 } </script> <link rel="stylesheet" href="static/css/bnt.css"> <script src="static/js/bnt.js"></script> </head> <body> <h1 >登录管理系统</h1> <form action="/sysuser/login" method="get" οnsubmit="return checksubmit()"> <table cellspacing="0px" > <tr> <td>用户名:</td> <td> <input type="text" name="username" id="user1" οnblur="checkusername()"> <span id="sp1"></span><br> </td> </tr> <tr> <td>密 码:</td> <td> <input type="password"name="pwd" id="pw1" οnblur="checkpassword()"> <span id="sp2"></span><br> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="登录"> <input type="reset" value="重置"> <button> <a href="register.html">注册</a> </button> </td> </tr> </form> </table> <img src="static/img/leaf.jpg"> </body> </html>
register.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> span{ font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; color: red; } </style> <script> //校验用户名 function checkusername(){ var reg=/^[a-zA-Z0-9]{6,10}$/ var usernameobj= document.getElementById("user1") var uservalue=usernameobj.value var usercheck=reg.test(uservalue) var sp1= document.getElementById("sp1") if(!usercheck){ sp1.innerText="用户名不正确" return false } sp1.innerText="OK" return true } //校验密码 function checkpassword(){ var reg=/^\d{6}$/ var pwdobj= document.getElementById("pw1") var pwdvalue=pwdobj.value var pwdcheck=reg.test(pwdvalue) var sp2= document.getElementById("sp2") if(!pwdcheck){ sp2.innerText="密码不正确" return false } sp2.innerText="OK" return true } //校验确认密码 function checkconformpassword(){ var reg=/^\d{6}$/ var pwdobj2= document.getElementById("pw2") var pwdvalue2=pwdobj2.value var pwdcheck2=reg.test(pwdvalue2) var sp3= document.getElementById("sp3") if(!pwdcheck2){ sp3.innerText="密码格式不正确" return false } //获取密码输入,并和确认密码比较是否相等 var pwdobj= document.getElementById("pw1") var pwdvalue=pwdobj.value if(pwdvalue2!=pwdvalue){ sp3.innerText="密码和确认密码不相等" return false } sp3.innerText="OK" return true } //表单提交校验 function checkregister(){ var flag1=checkpassword() var flag2=checkpassword() var flag3=checkconformpassword() return flag1&&flag2&&flag3 } </script> </head> <body> <h1 >登录管理系统</h1> <form action="/sysuser/register" method="get" οnsubmit="return checkregister()"> <table cellspacing="0px" > <tr> <td>用户名:</td> <td> <input type="text" name="username" id="user1" οnblur="checkusername()"> <span id="sp1"></span><br> </td> </tr> <tr> <td>密 码:</td> <td> <input type="password"name="userpwd" id="pw1" οnblur="checkpassword()"> <span id="sp2"></span><br> </td> </tr> <tr> <td>确认密 码:</td> <td> <input type="password" id="pw2" οnblur="checkconformpassword()"> <span id="sp3"></span><br> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="注册"> <input type="reset" value="重置"> <button> <a href="login.html">登录</a> </button> </td> </tr> </table> </form> </body> </html>