赞
踩
学习本章内容需要具备以下知识点
1,下载安装tomcat
官网:https://tomcat.apache.org/
解压下载的压缩包
进入解压好的文件,进入bin目录下C:\apache-tomcat-9.0.37-windows-x64\apache-tomcat-9.0.37\bin
显示cmd控制台代表启动完成(一闪而过代表你的电脑缺少java环境或者环境没有配置好)
解决控制台出现的日志中文乱码问题
打开conf文件夹/编辑logging.properties的配置文件将后面编码改为GBK
访问测试()
打开浏览器访问localhost:8080
tomcat访问的端口号修改
编辑conf/server.xml文件
如何关闭tomcat?
不要点击cmd窗口的关闭,再cmd窗口按下ctrl+会自动结束tomcat并关闭cmd窗口或者进入bin目录下带年纪shutdown.bat文件即可关闭
2,认识tomcat文件目录
目录
3,使用idea创建第一个web项目
我梦到了上帝,他对我说了一句helloword
新建一个空项目/在空项目里面新建一个模块
为它起个动听的名字,点击finish
目前创建了一个什么都没有的空模块,在模块名点击右键为他添加web服务支持
添加web服务后多了一个web文件夹,文件夹里面有个index.jsp
修改index.jsp
配置tomcat启动项
点击diea的run/editconfigrations
按照截图进行配置/找不到tomcat的到设置里下载插件
最后添加项目
添加完了启动项目
访问测试
1,转发和重定向的区别
package com.hai.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; /*转发与重定向的区别, 请求转发, 会携带数据, url不会改变, 属于服务器行为, 一次内部转发, 重定向, url发生改变, 不能携带请求参数, 属于客户端行为, 请求时至少发起两次以上的请求 */ public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); //接收用户名 String username = req.getParameter("username"); //接收用户密码 String password = req.getParameter("password"); //接收用户爱好选项 String[] hobbys = req.getParameterValues("hobbys"); System.out.println("======================"); //接收出现乱码 System.out.println(username+":"+password); System.out.println(Arrays.toString(hobbys)); System.out.println("======================"); //通过请求转发 req.getRequestDispatcher("/success.jsp").forward(req,resp); //以utf-8的编码格式进行定向转发 resp.setCharacterEncoding("utf-8"); //重定向注意路径,否则出现404 resp.sendRedirect("/r/success.jsp"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
jsp代码
<%-- Created by IntelliJ IDEA. User: admin Date: 2020/8/31 Time: 12:51 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户</title> </head> <body> <div> <form action="${pageContext.request.contextPath}/login" method="post"> 用户名:<label> <input type="text" name="username"> </label><br/> 密码:<label> <input type="password" name="password"> </label><br/> <!--df--> 爱好: <label> <input type="checkbox" name="hobbys" value="妹纸"> </label>妹纸 <label> <input type="checkbox" name="hobbys" value="代码"> </label>代码 <label> <input type="checkbox" name="hobbys" value="唱歌"> </label>唱歌 <label> <input type="checkbox" name="hobbys" value="电影"> </label>电影 <br/> <input type="submit" value="登录"> </form> </div> <%out.print(gae);%> <%String name = "jdo";%> <%out.print(name);%> <%!String gae = "20";%> </body> </html>
Request 和 Response 对象起到了服务器与客户机之间的信息传递作用。Request 对象用于接收客户端浏览器提交的数据,而 Response 对象的功能则是将服务器端的数据发送到客户端浏览器。 一、Request对象的五个集合: QueryString:用以获取客户端附在url地址后的查询字符串中的信息。 例如:stra=Request.QueryString ["strUserld"] Form:用以获取客户端在FORM表单中所输入的信息。(表单的method属性值需要为POST) 例如:stra=Request.Form["strUserld"] Cookies:用以获取客户端的Cookie信息。 例如:stra=Request.Cookies["strUserld"] ServerVariables:用以获取客户端发出的HTTP请求信息中的头信息及服务器端环境变量信息。 例如:stra=Request.ServerVariables["REMOTE_ADDR"],返回客户端IP地址 ClientCertificate:用以获取客户端的身份验证信息 例如:stra=Request.ClientCertificate["VALIDFORM"],对于要求安全验证的网站,返回有效起始日期。 二、Response对象 Response对象用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应。Response对象提供了一个数据集合cookie,它用于在客户端写入cookie值。若指定的cookie不存在,则创建它。若存在,则将自动进行更新。结果返回给客户端浏览器。 语法格式:Response.Cookies(CookieName)[(key)|.attribute]=value。这里的CookiesName是指定的Cookie的名称,如果指定了Key,则该Cookie就是一个字典,Attribute属性包括Domain,Expires,HasKeys,Path,Secure。 response的方法: Write:向客户端发送浏览器能够处理的各种数据,包括:html代码,脚本程序等。 Redirect:response.redirect("url")的作用是在服务器端重定向于另一个网页。 End:用来终止脚本程序。 Clear:要说到Clear方法,就必须提到response的Buffer属性,Buffer属性用来设置服务器端是否将页面先输出到缓冲区。语法为:Response.Buffer=True/False Flush:当Buffer的值为True时,Flush方法用于将缓冲区中的当前页面内容立刻输出到客户端。
概述:session是一次客户端与服务器的会话,当客户端于服务器建立连接时,session会创建一个唯一的sessionId,session的默认有限时间为30分钟,可以在web.xml文件中的session-config中进行修改,也可以通过session对象的setmaxInactiveInterval方法进行修改,值得注意的是,通过方法修改的参数单位是以秒钟为单位,
session常用的方法,
HttpSession接口源码
package javax.servlet.http; import java.util.Enumeration; import javax.servlet.ServletContext; public interface HttpSession { long getCreationTime();//获取创建session的时间戳 String getId();//获得session的ID long getLastAccessedTime();//获取上次session被访问的时间 ServletContext getServletContext();//获取servlet控制器的上下文 void setMaxInactiveInterval(int var1);//设置session的有效时间,以秒为单位 int getMaxInactiveInterval();//获取session的最大有效时间 /** @deprecated */ @Deprecated HttpSessionContext getSessionContext();//获取session的上下文 Object getAttribute(String var1);//获取session里的属性值 /** @deprecated */ @Deprecated Object getValue(String var1);//获得值 Enumeration<String> getAttributeNames();//获取所有的session属性 /** @deprecated */ @Deprecated String[] getValueNames();//获取多个值 void setAttribute(String var1, Object var2);//为session设置属性名和属性值, /** @deprecated */ @Deprecated void putValue(String var1, Object var2); void removeAttribute(String var1);//移除session里面的指定属性 /** @deprecated */ @Deprecated void removeValue(String var1); void invalidate();//移除session boolean isNew();//判断session是创建的 }
什么是Cookie??
概述:如果想让网页记住你的cookie和session的关系,cookie是依赖这session的,结合了session,首先session是由服务器创建的,服务器把sessionid给到了cookie,cookie数据保存在客户端的,客户端访问服务器的时候,就会把这和JSESSIONID交给cookie,cookie创建后,通过response对象的addCookie()将cookie添加,同获取
Cookie的常用方法
Cookie的源码
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package javax.servlet.http; import java.io.Serializable; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Locale; public class Cookie implements Cloneable, Serializable { private static final CookieNameValidator validation; private static final long serialVersionUID = 1L; private final String name; private String value; private int version = 0; private String comment; private String domain; private int maxAge = -1; private String path; private boolean secure; private boolean httpOnly; public Cookie(String name, String value) { validation.validate(name); this.name = name; this.value = value; } public void setComment(String purpose) { this.comment = purpose; } public String getComment() { return this.comment; } public void setDomain(String pattern) { this.domain = pattern.toLowerCase(Locale.ENGLISH); } public String getDomain() { return this.domain; } public void setMaxAge(int expiry) { this.maxAge = expiry; } public int getMaxAge() { return this.maxAge; } public void setPath(String uri) { this.path = uri; } public String getPath() { return this.path; } public void setSecure(boolean flag) { this.secure = flag; } public boolean getSecure() { return this.secure; } public String getName() { return this.name; } public void setValue(String newValue) { this.value = newValue; } public String getValue() { return this.value; } public int getVersion() { return this.version; } public void setVersion(int v) { this.version = v; } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException var2) { throw new RuntimeException(var2); } } public void setHttpOnly(boolean httpOnly) { this.httpOnly = httpOnly; } public boolean isHttpOnly() { return this.httpOnly; } static { boolean strictServletCompliance; String propStrictNaming; String propFwdSlashIsSeparator; if (System.getSecurityManager() == null) { strictServletCompliance = Boolean.getBoolean("org.apache.catalina.STRICT_SERVLET_COMPLIANCE"); propStrictNaming = System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING"); propFwdSlashIsSeparator = System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR"); } else { strictServletCompliance = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() { public Boolean run() { return Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE")); } }); propStrictNaming = (String)AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING"); } }); propFwdSlashIsSeparator = (String)AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR"); } }); } boolean strictNaming; if (propStrictNaming == null) { strictNaming = strictServletCompliance; } else { strictNaming = Boolean.parseBoolean(propStrictNaming); } boolean allowSlash; if (propFwdSlashIsSeparator == null) { allowSlash = !strictServletCompliance; } else { allowSlash = !Boolean.parseBoolean(propFwdSlashIsSeparator); } if (strictNaming) { validation = new RFC2109Validator(allowSlash); } else { validation = new RFC6265Validator(); } } }
全局作用域,作用域最高,作用于整个web服务器,一般用于统计网页访问量和文章浏览量等。。
认识相关类和接口
DriverManager //驱动管理器
Class //通过反射加载对应的数据库驱动
Statement //数据库操作对象
ResultSet //返回对象结果集
示例代码
package com.hai.dao; import java.sql.*; public class JDBCDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { //通过反射加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); //数据库相关参数 String url="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8"; String user = "root"; String password = "123456"; String sql = "select * from user"; //通过驱动管理器获得连接对象connection Connection connection = DriverManager.getConnection(url,user,password); //获得链接,操作数据库 Statement statement = connection.createStatement();//此方法存在sql注入 //执行sql语句并返回结果集 ResultSet resultSet = statement.executeQuery(sql); //遍历结果集 while (resultSet.next()){ //从数据库里获取第一个字段,字段名和数据库里的字段相对应 resultSet.getInt("id"); resultSet.getString("name"); resultSet.getString("pwd"); } //避免资源浪费,需要关闭资源,遵循先开后关顺序 resultSet.close(); statement.close(); connection.close(); //规范代码:应该本类处理异常, //资源关闭时在必执行代码块关闭 } }
每次使用都要写重复的代码,建议封装为工具类,创建一个数据库连接池
数据 库工具类的源代码
package gz.DBUtil; import java.sql.*; public class DBUtil { //数据库url private static final String URL = "jdbc:mysql://localhost:3306/qingshukeji?serverTimezone=GMT%2B8"; //用户名 private static final String USERNAME = "root"; //用户密码 private static final String PASSWORD = "123456"; //静态代码块加载数据库驱动 static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //获得数据库连接的方法 public static Connection getConn() { Connection conn = null; try { conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); } catch (SQLException e) { e.printStackTrace(); } return conn; } //关闭相应资源的方法,关闭操作对象和恶数据库连接 public static void close(PreparedStatement preparedStatement, Connection connection) { close(null, preparedStatement, connection); } //关闭三个资源 public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) { try{ if (resultSet != null) { resultSet.close(); } if (preparedStatement != null) { preparedStatement.close(); } if (resultSet != null) { connection.close(); } } catch (SQLException throwables) { throwables.printStackTrace(); } } }
SQL注入问题
createSteatement存在sql注入问题,应该使用preparedStatement防止sql注入,sql注入带来的影响是巨大的,不可挽回的损失,SQL注入攻击是通过操作输入来修改SQL语句,用以达到执行代码对WEB服务器进行攻击的方法。简单的说就是在post/getweb表单、输入域名或页面请求的查询字符串中插入SQL命令,最终使web服务器执行恶意命令的过程。可以通过一个例子简单说明SQL注入攻击。假设某网站页面显示时URL为http://www.example.com?test=123,此时URL实际向服务器传递了值为123的变量test,这表明当前页面是对数据库进行动态查询的结果。由此,我们可以在URL中插入恶意的SQL语句并进行执行。另外,在网站开发过程中,开发人员使用动态字符串构造SQL语句,用来创建所需的应用,这种情况下SQL语句在程序的执行过程中被动态的构造使用,可以根据不同的条件产生不同的SQL语句,比如需要根据不同的要求来查询数据库中的字段。这样的开发过程其实为SQL注入攻击留下了很多的可乘之机
sql注入模拟登录
public static void main(String[] args) throws SQLException {
String name = "'nicdshnvdjvhuylkvjifblavkfvnfk' or 5782=5782";
boolean execute = DBUtils
.getConn()
.prepareStatement("select * from user
where name='admin' and pwd="+name)
.executeQuery()
.next();
System.out.println(execute?"登录成功":"登陆失败");
}
可以看到在用户输入的密码于数据库密码不匹配也能成功登录
preparedStatement有效的解决了这个问题,使用?作为占位符,
public static boolean addUser() { String sql = "insert into user (id,name,pwd) values (?,?,?)"; Connection conn = DBUtils.getConn(); PreparedStatement statement = null; try { statement = conn.prepareStatement(sql); statement.setInt(1, 2); statement.setString(2, "laoli"); statement.setString(3, "020202"); int statementCount = statement.executeUpdate(); System.out.println(statementCount == 0 ? "添加失败" : "添加成功"); return true; } catch (Exception e) { e.printStackTrace(); return false; } finally { DBUtils.close(null, statement, conn); } }
public static boolean deleteUserById(int id){ String sql = "delete from user where id = ?"; Connection conn = DBUtils.getConn(); PreparedStatement statement = null; try{ statement = conn.prepareStatement(sql); statement.setInt(1,id); int statementCount = statement.executeUpdate(); System.out.println(statementCount==0?"删除失败":"删除成功"); return true; }catch(Exception e){ e.printStackTrace(); return false; }finally{ DBUtils.close(null,statement,conn); } }
public static boolean updateById(int id,String name,String pwd){ String sql = "update user set name=?,pwd=? WHERE id =?"; Connection conn = DBUtils.getConn(); PreparedStatement statement = null; try{ statement = conn.prepareStatement(sql); statement.setInt(3,id); statement.setString(1,name); statement.setString(2,pwd); int statementCount = statement.executeUpdate(); System.out.println(statementCount==0?"修改失败":"修改成功"); return true; }catch(Exception e){ e.printStackTrace(); return false; }finally{ DBUtils.close(null,statement,conn); } }
@SuppressWarnings("all") public static boolean queryUser() { String sql="select * from user"; Connection conn = DBUtils.getConn(); PreparedStatement statement = null; ResultSet resultSet = null; try { statement = conn.prepareStatement(sql); resultSet = statement.executeQuery(); while (resultSet.next()){ int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String pwd = resultSet.getString("pwd"); System.out.println("序号:"+id); System.out.println("用户名:"+name); System.out.println("用户密码:"+pwd); System.out.println("==================="); } return true; } catch (SQLException e) { e.printStackTrace(); return false; } finally { DBUtils.close(resultSet,statement,conn); } }
DAO(Data Access Object)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。
package com.hai.dao; import java.sql.*; import java.util.Objects; public class BaseDao { private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8"; private static final String USER_NAME = "root"; private static final String PASS_WORD = "123456"; public static Connection getConnection() { try { Class.forName(DRIVER); return DriverManager.getConnection(URL, USER_NAME, PASS_WORD); } catch (Exception e) { e.printStackTrace(); return null; } } public static void close(AutoCloseable... autoCloseables) { if (autoCloseables != null) { for (AutoCloseable autoCloseable : autoCloseables) { try { autoCloseable.close(); } catch (Exception e) { e.printStackTrace(); } } } } public static Object executeMethod(String sql,Object... params){ try { PreparedStatement statement = Objects.requireNonNull(getConnection()).prepareStatement(sql); if(params.length==0){ return statement.executeQuery(); } for (int i = 0; i < params.length; i++) { statement.setObject(i,params[i]); } close(statement); return statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); return 0; } } }
package com.hai.dao;
public interface UserDao {
Object deleteById(int id);
Object add(Object... params);
Object query();
Object update(Object... params);
}
package com.hai.dao.impl; import com.hai.dao.BaseDao; import com.hai.dao.UserDao; import java.sql.ResultSet; import java.sql.SQLException; public class UserDaoImpl implements UserDao { private String sql=""; @Override public Object deleteById(int id) { sql="delete from user where id = ?"; return BaseDao.executeMethod(sql,id); } @Override public Object add(Object... params) { sql="insert into user (id,name,pwd) values (?,?,?)"; return BaseDao.executeMethod(sql,params); } @Override public Object query() { sql="select * from user"; return BaseDao.executeMethod(sql); } @Override public Object update(Object... params) { sql="update user set id = ?, name=?,pwd=?"; return BaseDao.executeMethod(sql,params); } }
package com.hai.dao.test; import com.hai.dao.UserDao; import com.hai.dao.impl.UserDaoImpl; import java.sql.ResultSet; import java.sql.SQLException; public class JDBCTest { public static void main(String[] args) { UserDao userDao = new UserDaoImpl(); //增加 System.out.println((int)userDao.add(3, "老胡", "020203")>0?"添加成功":"添加失败"); //删除 System.out.println((int)userDao.deleteById(19)>0?"删除成功":"删除失败"); //修改 System.out.println((int)userDao.update("s3006", "沈老师", "2")>0?"修改成功":"修改失败"); //查询 ResultSet query =(ResultSet) userDao.query(); try{ while (query.next()){ System.out.println(query.getInt("id")); System.out.println(query.getString("name")); System.out.println(query.getString("pwd")); } } catch (SQLException throwables) { throwables.printStackTrace(); } } }
package com.hai.dao.pojo; public class User { private Integer id; private String name; private String pwd; public User(Integer id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public User() { } 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 String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
package com.hai.dao.test; import com.hai.dao.UserDao; import com.hai.dao.impl.UserDaoImpl; import com.hai.dao.pojo.User; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; public class JDBCTest { public static void main(String[] args) { UserDao userDao = new UserDaoImpl(); User user1 = new User(11, "老胡", "020203"); User user2 = new User(2,"沈老师", "2"); //增加 System.out.println((int)userDao.add(user1.getId(),user1.getName(),user1.getPwd())>0?"添加成功":"添加失败"); //删除 System.out.println((int)userDao.deleteById(user1.getId())>0?"删除成功":"删除失败"); //修改 System.out.println((int)userDao.update(user2.getName(),user2.getName(),user2.getId())>0?"修改成功":"修改失败"); //查询 ResultSet query =(ResultSet) userDao.query(); ArrayList<User> users = new ArrayList<>(); try{ while (query.next()){ User user = new User(); user.setId(query.getInt("id")); user.setName(query.getString("name")); user.setPwd(query.getString("pwd")); users.add(user); } } catch (SQLException throwables) { throwables.printStackTrace(); } for (User user : users) { System.out.println(user.toString()); } } }
添加成功
删除成功
修改成功
User{id=1, name='admin', pwd='123456'}
User{id=2, name='沈老师', pwd='沈老师'}
User{id=15, name='simisi', pwd='hcuisdgcudfu63'}
User{id=16, name='simisis', pwd='121212'}
User{id=20, name='18184278740', pwd='123456'}
User{id=21, name='18184278740', pwd='123456'}
User{id=22, name='18184278740', pwd='123456'}
Process finished with exit code 0
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisuserSSL=true&useUnicode=true&serverTimezone=UTC&characterEncoding=utf-8
username=root
password=123456
package com.hai.dao.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class GetProperties { private static final Properties properties; public static GetProperties getProperties; static { InputStream stream = GetProperties.class.getResourceAsStream("/database.properties"); properties = new Properties(); try { properties.load(stream); stream.close(); } catch (IOException e) { e.printStackTrace(); } } private GetProperties(){} public static GetProperties getInstance(){ if(getProperties==null){ getProperties = new GetProperties(); } return getProperties; } public String getParams(String key){ return properties.getProperty(key); } }
package com.hai.dao.utils;
public class InstanceTest {
public static void main(String[] args) {
System.out.println(GetProperties.getInstance().getParams("driver"));
System.out.println(GetProperties.getInstance().getParams("url"));
System.out.println(GetProperties.getInstance().getParams("username"));
System.out.println(GetProperties.getInstance().getParams("password"));
}
}
1,饿汉式单例(立即加载)
示例代码:
package com.hai.single; public class HungryManSingle { //饿汉式单例 private static final HungryManSingle hungryManSingle = new HungryManSingle(); //构造方法私有化,保证当前对象使用时全局唯一 private HungryManSingle(){} public static HungryManSingle newInstance(){ return hungryManSingle; } public void test(){ System.out.println("饿汉式单例"); } }
饿汉式单例new多个对象,虽然提高了效率但是浪费了空间,在类加载的时候对象已经完成初始化,通过调用方法返回该对象,属于空间换时间
2,懒汉式单例(延迟加载)
示例代码:
package com.hai.single; public class LazyManSingle { //懒汉式单例 private volatile static LazyManSingle lazyManSingle = null; //双重检测锁模式 public static LazyManSingle neInstance(){ if(lazyManSingle==null){ synchronized (LazyManSingle.class){ if(lazyManSingle==null){ lazyManSingle = new LazyManSingle(); } } } return lazyManSingle; } private LazyManSingle(){} public void test(){ System.out.println("懒汉式单例"); } }
解决线程安全,但是多线程情况下,需要线程进行排队,大大较低了执行效率,加锁的同时对实例进行了两次非空判断,并使用volatile关键字对当前对象添加了内存屏障,避免计算机cpu发出指令时发生指令重排。在类加载时不创建实例,在调用获取实例方法的时候才会创建实例,加载较慢,属于时间换空间
什么是数据库连接池??
:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
为什么需要数据库连接池??
:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。
数据库连接池的必要参数有哪些??
九个基本参数 | 按需所取 |
---|---|
username | 用户名 |
password | 密码 |
url | 数据库地址 |
driver | 连接驱动类 |
initialPoolSize | 初始化连接数 |
maxPoolSize | 最大连接数 |
minPoolSize | 最小连接数 |
maxStatements | 最长等待时间 |
maxIdleTime | 最大空闲时间 |
c3p0数据源示例代码:
package com.zww.server; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource; public final class ConnectionManager { //使用单利模式创建数据库连接池 private static ConnectionManager instance; private static ComboPooledDataSource dataSource; private ConnectionManager() throws SQLException, PropertyVetoException { dataSource = new ComboPooledDataSource(); dataSource.setUser("root"); //用户名 dataSource.setPassword("123456"); //密码 dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/zww");//数据库地址 dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setInitialPoolSize(5); //初始化连接数 dataSource.setMinPoolSize(1);//最小连接数 dataSource.setMaxPoolSize(10);//最大连接数 dataSource.setMaxStatements(50);//最长等待时间 dataSource.setMaxIdleTime(60);//最大空闲时间,单位毫秒 } public static final ConnectionManager getInstance() { if (instance == null) { try { instance = new ConnectionManager(); } catch (Exception e) { e.printStackTrace(); } } return instance; } public synchronized final Connection getConnection() { Connection conn = null; try { conn = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return conn; } }
在项目实际开发过程中,会将整个项目从上到下划分为页面层、业务逻辑层、数据层。
三层开发是项目开发实践中典型的开发模式。
目的:实现高内聚、低耦合。
分层的组成及作用
表示层:与用户交互、展示数据
业务逻辑层:控制业务流程及事务
数据访问层:实现数据库操作
分层优点
职责清晰,分工明确
利于维护扩展
利于代码重用
<jsp:useBean id="service" class="com.hai.service.impl.NewsDetailsServiceImpl" scope="application"/> //id是标签名,然后class是类路径,scope是作用域 <jsp:include page="newsDetailList.jsp"/> //引入公共jsp页面,在运行时将多个页面合成为同一个页面,page为目标页面 <%@include file="adminBottom.jsp"%> //引入公共jsp页面,与jsp:include不同的是,@include是编译时合成页面,贰jsp:include是运行时合成一个页面 <jsp:forward page="adminBottom.jsp"/> //实现页面跳转,page为目标页面,可通过parmas携带参数
1,下载相应依赖jar包
代码过于繁琐,简过·
分页查询的优点
分页查询的操作步骤
分页查询关键点
计算显示数据的总数量需要借助JDBC内容
计算页数时,声明一个工具类将功能独立出来,便于复用
总记录数/每页显示的记录数
整除:总页数=总记录数/每页显示记录数
不能整除:总页数=总记录数/每页显示记录数+1
实现代码
DAO层
@Override public List<NewsDetails> getNewsDetailsListLimit(int pageNumber, int pageSize) { ArrayList<NewsDetails> newsDetails = new ArrayList<>(); String sql = "select * from `news_detail` limit "+(pageNumber - 1) * pageSize+","+pageSize; ResultSet resultSet = (ResultSet) BaseDao.executeMethod(sql); return getNewsDetails(newsDetails, resultSet); } private List<NewsDetails> getNewsDetails(ArrayList<NewsDetails> newsDetails, ResultSet resultSet) { try { while (resultSet.next()) { NewsDetails details = new NewsDetails(); details.setId(resultSet.getInt("id")); details.setAuthor(resultSet.getString("author")); details.setCategoryId(resultSet.getInt("categoryId")); details.setContent(resultSet.getString("content")); details.setCreateDate(resultSet.getDate("createDate")); details.setModifyDate(resultSet.getDate("modifyDate")); details.setPicPath(resultSet.getString("picPath")); details.setTitle(resultSet.getString("title")); details.setSummary(resultSet.getString("summary")); newsDetails.add(details); } } catch (SQLException e) { e.printStackTrace(); } return newsDetails; }
Service层
@Override
public List<NewsDetails> getNewsDetailsListLimit(int pageNumber, int pageSize) {
return newsDetailsDao.getNewsDetailsListLimit(pageNumber,pageSize);
}
测试
package com.hai.test;
import com.hai.entity.NewsDetails;
import com.hai.service.impl.NewsDetailsServiceImpl;
public class AllTest {
public static void main(String[] args) {
for (NewsDetails newsDetails : new NewsDetailsServiceImpl().getNewsDetailsListLimit(1, 2)) {
System.out.println(newsDetails.toString());
}
}
}
测试结果
四个域的寻找顺序分别为page, request,session,application。用EL表达式还有一个好处,如果找不到键值为name的属性值,不会显示null,会显示空的字符串,若确定键值是在request域中,则可以用如下EL表达式代码
${requestScope.name}
执行运算符
获取常用对象
语法:${隐式对象名称}
隐式对象表
对象名 | 用法 | 等价于JSP代码或作用 |
---|---|---|
param | ${param.name} | request.getParameter(name) |
paramValues | ${paramValues.name} | request.getParameterValues(name) |
header | ${header.name} | request.getHeader(name) |
headerValues | ${headerValues.name} | request.getHeaderValues(name) |
cookie | ${cookie.name.value} | request.getCookie() |
initParam | ${initParam.name} | ServletContext.getInitparameter(name) |
pageContext | ${pageContext.request.contextPath} | 获取web项目名 |
pageContext | ${pageContext.request.sessionid} | 获取sessionid |
pageContext | ${pageContext.request.remoteAddr} | 获取主机名 |
显示方式
对象信息展示
<% NewsDetails newsDetails = new NewsDetails(); newsDetails.setTitle("军事"); newsDetails.setCreateDate(new Date()); newsDetails.setSummary("台湾回归"); newsDetails.setPicPath("www.qliyunbeijing"); newsDetails.setContent("祖国71周岁生日"); request.setAttribute("newsDetails",newsDetails); %> 获取对象信息:${newsDetails.title} 获取对象信息:${newsDetails.createDate} 获取对象信息:${newsDetails.summary} 获取对象信息:${newsDetails.picPath} 获取对象信息:${newsDetails.content} 也可以用${newsDetails['title']}
集合信息展示
<%
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
request.setAttribute("arrayList",list);
%>
获取集合信息:${arrayList[0]}
获取集合信息:${arrayList[1]}
获取集合信息:${arrayList[2]}
获取集合信息:${arrayList[3]}
Map集合通过key获取vaule
<%
HashMap<Object, Object> map = new HashMap<>();
map.put("name","老李");
map.put("age","21");
map.put("address","广东深圳");
map.put("weight","60kg");
request.setAttribute("mapInfo",map);
%>
获取map集合信息:${mapInfo.name}
获取map集合信息:${mapInfo.age}
获取map集合信息:${mapInfo.weight}
获取map集合信息:${mapInfo.address}
网页展示效果
JSTL需要和EL表达式联合使用,先两个下载jar包
引入
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用
踩坑:引入后项目启动报错org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.jsp.index_jsp
解决方案:jstl和standard两个jar包都引入即可,
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> <h1>JSTL</h1> <hr/> c:out //输出语句<br/> c:set //设置变量<br/> c:remove //移除变量<br/> <c:out value="${massage}" default="not hava value"/><br/>//default代表要输出的值为null时输出default的值 <c:set var="massage" value="hello JSTL"/><br/>//设置一个变量名为massage的变量并赋值为hello JSTL <c:out value="${massage}"/><br/> <c:remove var="massage"/><br/>//移除变量 <c:out value="${massage}" default="massage is a not defined"/><br/> <c:foreach var="newProperty" items="${list}" varStatus="staIndex">//循环遍历输出集合对象 <tr>//var为新变量名也就是遍历之后获得的属性值会赋值给var //items为被遍历的集合或数组、 //varStatus为遍历计数索引 //varStatus.first判断是否为第一次遍历 //varStatus.last判断是否是最后一次遍历 //varStatus.count累计循环次数 //varStatus.index获得当前遍历的索引号 <td>${newProperty.name}</td> <td>${newProperty.age}</td> <td>${newProperty.weight}</td> </tr> </c:foreach> <c:if test="${1==1}">//if为判断条件是否成立 //条件成立执行体 </c:if> <%--外部url引入 参数标签,与超链接一起被携带--%>
JSTL标签测试
<%–导入资源标签–%>
<c:import url=“index.jsp”/>
</body> </html> ``` - 格式化标签库 - 导入 ```jsp <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> ``` - 使用 ```jsp <fmt:ofrmatDate value="${new date()}" pattern="yyyy-MM-dd HH:mm:ss"/> ``` - 详情见帮助文档 常用标签总结 ```jsp EL表达式 . [ ] 算术、关系、逻辑等运算符 访问作用域:pageScope、 requestScope、sessionScope、 applicationScope JSTL标签 <c:out />、//输出 <c:set/>、//设置 <c:remove/> //移除 <c:if/>、//判断 <c:forEach/> //循环 <c:url/>、//超链接 <c:param/>、//参数携带 <c:import/> //引入资源 <fmt:formatDate/>、//日期格式化 <fmt:formatNumber/> //数字格式化 ```
什么是servlet?
为什么需要servlet?
servlet做了什么?
理解Servlet生命周期
创建和部署Servlet
使用前先引入jar包(javax.servlet-api-4.0.1.jar)
servlet创建的三种方式
package com.hai.servlet; import javax.servlet.*; import java.io.IOException; public class HelloServlet implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("servlet创建时调用的初始化方法"); } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("所有的请求都会经过的方法"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { System.out.println("servlet声明周期结束时调用"); } }
package com.hai.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class HelloGenericServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("所有请求都经过的方法,用来处理servlet请求");
}
}
package com.hai.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HelloHttpServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } } //需要什么方法就重写什么方法,继承时并不强制的要求实现方法,
三种创建方式均需配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <!-- 为servlet起的名称--> <servlet-name>HelloServlet</servlet-name> <!-- 类的路径,包名和类名 --> <servlet-class>com.hai.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <!-- 注册映射,需要跟上面起的名称一致--> <servlet-name>HelloServlet</servlet-name> <!-- 映射请求的请求名字--> <url-pattern>/HelloServlet</url-pattern> </servlet-mapping> <servlet> <!-- 为servlet起的名称--> <servlet-name>HelloGenericServlet</servlet-name> <!-- 类的路径,包名和类名 --> <servlet-class>com.hai.servlet.HelloGenericServlet</servlet-class> </servlet> <servlet-mapping> <!-- 注册映射,需要跟上面起的名称一致--> <servlet-name>HelloGenericServlet</servlet-name> <!-- 映射请求的请求名字--> <url-pattern>/HelloGenericServlet</url-pattern> </servlet-mapping> <servlet> <!-- 为servlet起的名称--> <servlet-name>HelloHttpServlet</servlet-name> <!-- 类的路径,包名和类名 --> <servlet-class>com.hai.servlet.HelloHttpServlet</servlet-class> </servlet> <servlet-mapping> <!-- 注册映射,需要跟上面起的名称一致--> <servlet-name>HelloHttpServlet</servlet-name> <!-- 映射请求的请求名字--> <url-pattern>/HelloHttpServlet</url-pattern> </servlet-mapping> </web-app>
web.xml配置理解
<servlet-mapping> <servlet-name>HelloHttpServlet</servlet-name> <!-- 请求为/HelloHttpServlet --> <url-pattern>/HelloHttpServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>HelloHttpServlet</servlet-name> <!-- 请求为/dev/HelloHttpServlet --> <url-pattern>/dev/HelloHttpServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>HelloHttpServlet</servlet-name> <!-- 请求为/HelloHttpServlet下的所有请求路径 --> <url-pattern>/HelloHttpServlet/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>HelloHttpServlet</servlet-name> <!-- 请求路径后缀为.jsp的都会经过这个请求 --> <url-pattern>*.jsp</url-pattern> </servlet-mapping>
<servlet>
<servlet-name>HaiServlet</servlet-name>
<servlet-class>com.hai.servlet.HaiServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
@Override
public void init(ServletConfig config) throws ServletException {
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
System.out.println(username+":"+password);
}
基本概念
在请求发起的时候,有过滤器拦截到,统一的进行处理,例如在每次servlet请求我们都需要设置请求和响应的编码为utf-8,有没有什么方法能让我们设置一次编码,然后在每个servlet中都有效呢,这个时候就体现了过滤器的优点,
编码过滤器实现代码(实现Filter接口,不要导错包!):
package com.hai.filter; import javax.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //过滤请求编码 servletRequest.setCharacterEncoding("utf-8"); //过滤响应编码 servletResponse.setCharacterEncoding("utf-8"); //过滤后给予放行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("服务器启动时调用此方法,完成过滤器初始化"); } @Override public void destroy() { System.out.println("服务器关闭时销毁过滤器"); } }
配置web.xml
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.hai.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!-- /*代表拦截所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter初始化参数(同Servlet):
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.hai.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
获取参数
package com.hai.filter; import javax.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { FilterConfig f;//提升FilterConfig作用域作为全局变量来供给方法获取初始化参数 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //过滤请求编码 servletRequest.setCharacterEncoding(f.getInitParameter("encoding")); //过滤响应编码 servletResponse.setCharacterEncoding(f.getInitParameter("encoding")); //过滤后给予放行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void init(FilterConfig filterConfig) throws ServletException { this.f = filterConfig;//赋值提升作用域 System.out.println("服务器启动时调用此方法,完成过滤器初始化"); } @Override public void destroy() { System.out.println("服务器关闭时销毁过滤器"); } }
Filter工作流程
拦截链路理解(多个Filter过滤同一个请求时形成拦截链路):
类似于jvm的压栈,最开始执行的拦截器最后一个结束拦截
什么是监听器?
web八大监听器
使用HttpSessionBindingListener监听器实现网站在线人数监测案例
监听器代码(踩坑:监听器实现需要与添加到session的数据处于同一个类,否则监听器不生效)
package com.hai.entity.vo; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class User implements HttpSessionBindingListener { private int id; private String username; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public void valueBound(HttpSessionBindingEvent event) { System.out.println("session里面保存新对象时该方法会调用,监听保存了的user对象"); ConStatus.ONLINE_USER++; } @Override public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("session里面的user对象被销毁时触发该事件"); ConStatus.ONLINE_USER--; } }
常量统计类
package com.hai.entity.vo;
public class ConStatus {
public static int ONLINE_USER=0;
}
servlet代码
package com.hai.servlet; import com.hai.entity.vo.User; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class OnlineServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); if (username == null && username.equals("")) { resp.sendRedirect("index.jsp"); }else { User user = new User(); user.setUsername(username); req.getSession().setAttribute("user",user); req.getRequestDispatcher("ass.jsp").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
package com.hai.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getSession().invalidate(); resp.sendRedirect("index.jsp"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
前端代码
<%-- Created by IntelliJ IDEA. User: admin Date: 2020/11/4 Time: 14:02 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> <form action="${pageContext.request.contextPath}/OnlineServlet"> <input type="text" name="username"> <input type="submit" value="登录"> </form> </body> </html>
<%@ page import="com.hai.entity.vo.User" %> <%@ page import="com.hai.entity.vo.ConStatus" %><%-- Created by IntelliJ IDEA. User: admin Date: 2020/11/4 Time: 14:53 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 用户名:<%User user = (User)session.getAttribute("user");%><%=user.getUsername()%> 在线人数:<%=ConStatus.ONLINE_USER%>人 <p><a href="${pageContext.request.contextPath}/LogoutServlet">离开</a></p> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>OnlineServlet</servlet-name> <servlet-class>com.hai.servlet.OnlineServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>OnlineServlet</servlet-name> <url-pattern>/OnlineServlet</url-pattern> </servlet-mapping> <servlet> <servlet-name>LogoutServlet</servlet-name> <servlet-class>com.hai.servlet.LogoutServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LogoutServlet</servlet-name> <url-pattern>/LogoutServlet</url-pattern> </servlet-mapping> <listener> <listener-class>com.hai.listener.OnlineListener</listener-class> </listener> </web-app>
效果展示
MVC理解
MVC处理流程
MVC优缺点
处理流程再理解
什么是ajax?
为什么需要ajax?
ajax的优点
ajax的执行流程
ajax实现的两种方式
使用JavaScript的原生js实现
<%-- Created by IntelliJ IDEA. User: admin Date: 2020/11/5 Time: 14:41 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> <script type="text/javascript" src="statics/js/jquery-3.4.1.js"></script> <script> //失去焦点时调用此函数 function isyes() { //创建请求 let httpRequest = new XMLHttpRequest(); //获取输入框中的值 let username = $("#username").val(); //过滤空字符 if (username == null) { alert("用户名不能为空") } else { //响应请求的回调函数 httpRequest.onreadystatechange = callBack; //请求服务器的url let url = "UserServlet?username=" + username; //封装请求,以POST方式请求,封装写好的url,true代表为异步请求/false代表同步请求 httpRequest.open("POST", url, true); //封装完请求之后发送这个请求 httpRequest.send(); } function callBack() { //就绪状态为4且状态码为200代表请求成功 if (httpRequest.readyState === 4) { if (httpRequest.status === 200) { //拿到响应过来的数据 let responseData = httpRequest.responseText; //将数据写到span标签里面 $("#tip").html(responseData); } } } } </script> </head> <body> <form> <label> <input type="text" name="username" id="username" οnblur="isyes();"> </label><span id="tip"></span> <p><input type="submit"></p> </form> </body> </html>
package com.ajax.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html"); String username = req.getParameter("username"); if(username.equals("老李呀")){ resp.getWriter().print("<span style=\"color: red\">Someone already uses this nickname. Please use another nickname<span/>"); }else { resp.getWriter().print("<span style=\"color: green\">This nickname can be used<span/>"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.ajax.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern>
</servlet-mapping>
</web-app>
使用jQuery封装好的ajax实现
<%-- Created by IntelliJ IDEA. User: admin Date: 2020/11/5 Time: 15:35 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title> </title> <script type="text/javascript" src="statics/js/jquery-3.4.1.js"></script> <script> //失去焦点调用函数 function isyes() { //封装好的ajax请求 $.ajax({ //请求url url: "UserServlet", //请求的方式 method: "get", //请求的数据,以json形式传递 data: {"username":$("#username").val()}, //请求的数据类型 dataType: "text", //请求成功调用的函数 success: function (data) { $("#tip").html(data); }, //请求失败调用的函数 error: function (data) { $("#tip").html(data); } }) } </script> </head> <body> <form> <label> <input type="text" name="username" id="username" οnblur="isyes();"> </label><span id="tip"></span> <p><input type="submit" value="提交"></p> </form> </body> </html>
什么是JSON?
JSON的优点有哪些?
JSON实例语法:
{ "username":"missLi", "age":21, "address":"云南省昭通市盐津县兴隆乡", "phone":"18184278740", "weight":"60kg", "sex":"男", "goWhere":[ "云南", "四川", "广东", "湖南", "广西", "贵州", "北京" ] };
json数据如何在web页面展示
{ "username":"missLi", "age":21, "address":"云南省昭通市盐津县兴隆乡", "phone":"18184278740", "weight":"60kg", "sex":"男", "goWhere":[ "云南", "四川", "广东", "湖南", "广西", "贵州", "北京" ] };
<script type="text/javascript" src="statics/js/jquery-3.4.1.js"></script> <script> //失去焦点调用函数 function isyes() { //封装好的ajax请求 $.ajax({ //请求url url: "UserServlet", //请求的方式 method: "get", //请求的数据,以json形式传递 data: {"username":$("#username").val()}, //请求的数据格式 dataType: "json", //请求成功调用的函数 success: function (data) { $("#tip").html(data); //提取json数据中的属性 let name = data.name; let age = data.age; }, //请求失败调用的函数 error: function (data) { $("#tip").html(data); } }) } </script>
结语:javaweb是整个学习开发的过程中最痛苦的一点,以后春天就来了
linux常用指令
shutdown -h now #关机 ls #查看文件或者文件夹 ls –l #以列表的形式查看文件 ls –a #可以查看隐藏的文件 ls –l –a #以列表的形式查看文件,包括隐藏文件 ll #以列表的形式查看文件 pwd #查看当前目录 cd .. #返回上一级目录 cd / #进到根目录 cd home #进到家目录(查看普通用户) cd ~ #进到超级管理员的家目录 mkdir #文件夹名称 创建单个文件夹 mkdir -p a/b/c #创建多级文件夹 clear #清屏 rmdir #删除文件夹 rm -rf #删除多级文件夹 touch #创建文件 rm -r #删除文件之前询问一下,回答yes删除,回答no不删除 #移动mv move缩写: 文件名称 目的地 mv 修改名字: mv 原名称 新名称 拷贝cp copy缩写: cp 第一个文件原目的地 目的地 Linux 文件操作命令 head 文件名 查看前10行内容 head –3:查看前3行 tail 文件名 查看后10行内容 tail –F:动态加载查看文件的内容变化 tail –3:查看文件后3行的内容 vi命令 vi 文件名称 :打开文件 相当于notepad vim 文件名称:打开文件 相当于notepad++ 按下i键 insert缩写 进入编辑模式 在某个文字之前写内容 按下a键 after缩写 进入编辑模式 在某个文字之后写内容 按下 Esc 键 :退出编辑模式 按下 :冒号,进入命令模式 按下:wq 保存并退出 按下:q 直接退出 按下:x 直接退出 按下:q! 退出但不保存: 按下:w 保存 Linux权限操作命令 su 用户名 切换用户 exit 退出上一层用户来操作 whoami 查看当前用户UID groups 查看当前用户所在的用户组GID id 查看用户ID和组ID 创建新用户 :useradd 用户名 创建新用户并制定用户ID:useradd -u 1001 用户名 tail /etc/passwd查看用户信息 passwd [用户名]:修改用户密码 userdel 用户名 :删除用户 usermod -l 新用户名 老用户名 usermod -g 新组名称 用户名 groupadd 组名 groupmod -g 新组ID 现有用户名 drwxr-xr-x d文件夹 rwx 拥有者u用户的权限 ,可读r,可写w,可执行x r-x 组用户g,可读,不可写,可执行 r-x 其他用户o,可读,不可写,可执行 权限模式 chmod –r U+X,G+W 文件名 数字模式 chmod 753 –r 文件名
认识linux文件夹
/ #linux系统根目录
/bin #系统启动时需要执行二进制文件
/dev #设备文件目录
/etc #操作系统的配置文件目录
/home #用户信息存放的目录,用户的默认工作目录
/user #程序和数据存放目录
/var #包含在正常操作中被改变的文件,假脱机文件,记录文件,临时文件和页格式化文件
使用Xshell连接远程服务器或者本地虚拟机
下载Xshell:https://www.netsarang.com/zh/free-for-home-school
新建会话连接
输入服务器或虚拟机的连接信息
输入服务器的用户名跟密码
连接成功后显示会用户名
使用xftp连接服务器和上传文件至服务器
下载xftp:https://www.xshellcn.com/xiazai.html
安装后通过xshell直连xftp
首先连接xshell
点击这个浅绿色的小文件夹图标直接发起连接
连接成功
文件上传:将本地文件拖拽至服务器的目标目录即可
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。