Servlet和jsp
b/s:浏览器请求,服务器响应
c/s:客户端请求,服务器响应
资源:
动态资源(jsp,servlet):不同用户访问同一动态资源的时候得到的结果可能会不一样
静态资源(jpg,png,css,js,html):不同用户访问同一静态资源时得到的结果一样
Servlet
即server applet,运行在服务器上的小程序,定义了一套浏览器如何访问服务器的规则,本质上是一个接口Servlet
生命周期
创建Servlet对象后---------->初始化(调用 init () 方法)--------->处理/响应客户端的请求(调用 service() 方法)--------->销毁(调用 destroy() 方法,最后由 JVM 的垃圾回收器进行垃圾回收)
一
-
首先定义类并实现Servlet接口,重写其中的方法
方法 作用 init
servlet的初始化方法,当第一次访问该servlet的时候执行该初始化方法(生命周期可以更改,可以通过修改初始化方法,令服务器一启动就执行初始化方法(如下))
service
servlet的服务方法每一次访问该servlet的时候都会执行该服务方法
destroy
servlet的销毁方法,当服务器正常关闭时,执行该销毁方法
-
web.xml的配置文件,如下
二
-
与一相同,继承Servlet接口
-
无需在web.xml中进行配置,而是通过@WebServlet注解,可以代替web.xml中所有关于该servlet的配置,将url填写在该注解后的括号中
三
-
直接继承GenericServlet类,GenericServlet是一个抽象类,对init和destroy方法进行了空实现,只需实现service方法
-
同样使用注解
四(请求)
-
继承HttpServlet,重写doGet和doPost方法,默认请求方式为get,所以默认调用doGet方法,当请请求方式为post时调用doPost方法(可采用嵌套方式,即在doGet方法内调用doPost方法,这样,无论使用什么请求都会调用doPost方法)
-
新建jsp页面
get请求和post请求的区别
get请求:在地址栏中拼接参数,参数不能存放太大,大概2k左右,相对来说不安全;查询效率高于post请求;get请求没有请求体,只有query string
post请求:请求参数放在请求体中,相对来说更安全,查询效率没有get高
五(注解写法)
使用@WebServlet注解时,可使用多种方法
-
第一种:@WebServlet("/servletDemo5")
-
第二种(多路径写法):@WebServlet({"/xxx","/yyy"})
-
第三种(只要后缀为.can的路径都可以访问):@WebServlet("*.can")
-
第四种(只要前缀为/user/的路径都可以访问):@WebServlet("/user/*")
-
第五种(可以绑定所有,但优先级低于已经绑定的url,并且可以访问.jsp后缀的文件(当地址栏输入xxx.jsp时会跳转到jsp页面),而不会跳转到servletDemo5):@WebServlet("/")
-
第六种(可以绑定所有,但优先级低于已经绑定的url,匹配不到.jsp后缀的文件(当地址栏输入xxx.jsp时会匹配为servletDemo5),并且会把.jsp后缀的文件匹配到servletDemo5):@WebServlet("/*")
Request
参数中的request是客户端传入的,即doGet和doPost方法的形参
中文乱码问题
request.setCharacterEncoding("utf-8");
获取参数(表单中name属性的值)
String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println(username+":"+password);
路径
System.out.println(request.getRequestURL());// 完整路径 System.out.println(request.getRequestURI());// 部分路径
获取地址栏拼接参数(只有get请求有)(略)
System.out.println(request.getQueryString());
获取请求头中的值(略)
System.out.println(request.getHeader("Host"));
域对象
四大域对象(page(jsp有效),request(一次请求),session(一次会话),servletContext(application--jsp中的名字)(当前web应用))
// 域对象:能够在一定的范围内共享数据 // request的作用域在一次请求和一次响应之间 // xxx.setAttribute即为设置域对象 request.setAttribute("username","张三");// 参数为“名值对” //由于request作用范围是一次请求一次响应,浏览器访问requestDemo1视为一次请求,若要获取username的值,就需要在本次响应中返回,而不能再次调用requestDemo2进行返回,但可以使用请求转发,如下 System.out.println(request.getAttribute("username"));
请求转发
// 当访问requestDemo1时,地址栏仍为requestDemo1,但由requestDemo2返回值,不能跳转到外部资源 // 由于请求转发是一次请求,所以使用请求转发,仍可以调用到requestDemo2,可以获取username的值,而不需要在地址栏输入进行二次请求 // 获取请求转发器 RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo2"); // 请求转发 requestDispatcher.forward(request,response);
实例
登录功能
@WebServlet("/requestLoginTest") public class RequestLoginTest extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取表单中的账号密码 String username = request.getParameter("username"); String password = request.getParameter("password"); // 获取到登录页面和登陆成功页面的请求转发器 RequestDispatcher requestDispatcher1 = request.getRequestDispatcher("/login.jsp"); RequestDispatcher requestDispatcher2 = request.getRequestDispatcher("/successful.jsp"); // 账号密码判断 if (username.equals("zhangsan")) { if (password.equals("123456")) { // 登录成功,通过请求转发跳转到登陆成功页面 requestDispatcher2.forward(request,response); } else { // 设置域对象,用于在登录页面通过${requestScope.end}展示值 request.setAttribute("end","密码错误"); requestDispatcher1.forward(request,response); } } else { request.setAttribute("end","账号错误"); requestDispatcher1.forward(request,response); } } }
Response
常见响应状态码:
-
200:成功响应,正常的状态码
-
302:重定向,正常的状态码
-
404:请求资源找不到(查看访问的路径是否正确,查看访问的资源福否被编译进out目录)
-
405:请求的方法不允许(后端无法接收前端的请求方式)
-
403:请求被拒绝(在爬虫中加上请求头user-agent)
-
500:服务器内部出错(在idea控制台中查看报错信息)
乱码问题
response.setContentType("text/html;charset=utf-8");
写入数据
// 将数据写给前端,在没有处理的情况下会直接显示在前端网页上 response.getWriter().write("张三");
重定向
response.sendRedirect("/login.jsp");
请求转发和重定向
请求转发 | 重定向 |
---|---|
一次请求 | 两次请求 |
在服务器内部进行资源跳转,不能访问外部资源 | 服务器会告诉浏览器访问什么资源,可以访问外部资源 |
地址栏没有发生变化 | 地址栏发生了变化 |
浏览器不知道服务器内部做了什么 | 浏览器接收到重定向的消息后再进行访问 |
Cookie
会话(多次请求,多次响应)技术,运行在客户端上
解决多次请求和多次响应之间共享数据的问题
创建cookie
// value可以存储中文,但在存储空格时需要进行编码和解码 String value = "月 亮"; String encode = URLEncoder.encode(value, "utf-8"); Cookie cookie = new Cookie("name",encode);
添加cookie
// cookie的存储时间默认在浏览器关闭后就消失 // 设置getMaxAge();可让关闭后还能存在 // 当参数为正整数时,是多少就是多少秒 // 当参数为0时,删除该cookie // 当参数为-1时,就是默认情况 cookie.getMaxAge(); // 把cookie添加到响应中,让浏览器能存储它 response.addCookie(cookie);
拿到请求中的cookie
Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { String name = cookie.getName(); // 解码 if ("name".equals(name)) { String value = cookie.getValue(); String decode = URLDecoder.decode(value,"utf-8"); System.out.println(name+":"+decode); } }
实例
登录注册
@WebServlet("/cookieLoginTest") public class CookieLoginTest extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 解决乱码问题 request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); RequestDispatcher requestDispatcher = request.getRequestDispatcher("/login.jsp"); // 标志位,判断是否是第一次登录 boolean flag = true; if (username.equals("zhangsan")) { if (password.equals("123456")) { // 登陆成功时,记录登录时间 Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String format1 = format.format(date); // 遍历cookie Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { String name = cookie.getName(); // 第一次访问时,没有名为name的cookie,所以不进入该if if (name.equals("name")) { String value = cookie.getValue(); String decode = URLDecoder.decode(value, "utf-8"); response.getWriter().write( "欢迎,您上次登录的时间为" + decode); flag = false; } } if (flag) { //request.setAttribute("welcome", "欢迎,这是您第一次登录"); //requestDispatcher.forward(request, response); // 将数据写给前端(使用cookie时,尽量不使用请求转发)? response.getWriter().write("欢迎,这是您第一次登录!"); } // 将时间添加到cookie中 String encode = URLEncoder.encode(format1, "utf-8"); Cookie cookie1 = new Cookie("name", encode); response.addCookie(cookie1); } else { request.setAttribute("end", "密码错误"); // 使用请求转发,如果使用了request域,使用重定向后,request就失效了,因为超出了作用域范围 requestDispatcher.forward(request, response); } } else { request.setAttribute("end", "账号不存在"); requestDispatcher.forward(request, response); } } }
Session
会话技术,存储在服务器上(相对于cookie更加安全)
session依赖cookie而存活,当浏览器第一次访问服务器时,会生成一把“钥匙”,即Set-Cookie:JSESSIONID=xxx,在后续的访问中,浏览器都会携带该同一钥匙,若钥匙相同,则可以访问到服务器获取值;在关闭浏览器后,cookie销毁,重启浏览器,会重新生成一把“钥匙”,由于重新生成的钥匙和原钥匙不匹配,所以无法得到相应的值,要解决该问题就需要增大cookie的生命周期
拿到session对象
HttpSession session = request.getSession();
设置域对象
session.setAttribute("name","zhangsan");
设置生命周期添加
// 让浏览器关闭后再启动依旧能访问到服务器中的session数据(增大cookie的生命周期) // 拿到当前session的钥匙,JSESSIONID的值,并设置存活时间 String id = session.getId(); Cookie cookie = new Cookie("JSESSIONID",id); cookie.setMaxAge(500); response.addCookie(cookie);
ServletContext
作用域为全局
得到对象添加值
javax.servlet.ServletContext servletContext = request.getServletContext(); servletContext.setAttribute("config","xxxxx");
Filter过滤器
1.通过@WebFilter()对指定文件进行过滤,括号中为需要过滤的文件
2.在doFilter方法中对过滤的文件进行操作
3.放行
filterChain.doFilter(servletRequest,servletResponse);
实例
对所有文件进行拦截,只放行login.jsp页面和requestLoginTest,若登录成功后,可以访问所有文件
// requestLoginTest @WebServlet("/requestLoginTest") public class RequestLoginTest extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); HttpSession session = request.getSession(); if (username.equals("zhangsan")) { if (password.equals("123456")) { // 新建session域对象,标志位判断是否登陆成功 session.setAttribute("flag", true); // 若之前输入账号密码出现错误,会出现提示,在登录成功后删除提示 session.removeAttribute("name"); session.removeAttribute("pass"); // 登陆成功,重定向到登陆成功页面 response.sendRedirect("/successful.jsp"); } else { // 标志位判断没有登录成功过,在过滤器中就不会放行 session.setAttribute("flag", false); // 域对象,用于显示在login.jsp界面提示用户 session.setAttribute("pass","密码错误"); // 当密码错误时,会删除账号不存在的提示,而出现密码错误的提示 session.removeAttribute("name"); response.sendRedirect("/login.jsp"); } } else { session.setAttribute("flag", false); session.setAttribute("name","账号不存在"); session.removeAttribute("pass"); response.sendRedirect("/login.jsp"); } } }
// 过滤器 @WebFilter("/*")// 可以对所有文件进行过滤 public class FilterTest implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; // 放行与登录相关的页面 if (httpServletRequest.getRequestURI().equals("/login.jsp") || httpServletRequest.getRequestURI().equals("/requestLoginTest")) { filterChain.doFilter(httpServletRequest,httpServletResponse); } else { // 与登录不相关时,进行判断,是否成功登陆过 Object flag = httpServletRequest.getSession().getAttribute("flag"); if (flag == null) { httpServletResponse.sendRedirect("/login.jsp"); } else { // 不为空时,判断标志位 Boolean Tflag = (Boolean) flag; // 如果标志位为true,说明成功登陆过,放行 if (Tflag) { filterChain.doFilter(httpServletRequest,httpServletResponse); } else { httpServletResponse.sendRedirect("/login.jsp"); } } } } @Override public void destroy() { Filter.super.destroy(); } }
JSP
java server pages
jsp脚本
用于嵌入java代码使用的脚本
1.该脚本放置在该jsp被编译后的servlet类中的service方法中
<% System.out.println("hello"); int a = 5; %>
2.该脚本用于输出到页面上
<%= a %>
3.该脚本作为全局变量来使用,放在类体里面
<%! int b = 5; %>
jsp指令
用于配置技术jsp页面使用的
指令格式:<%@ %>
1.page指令
其中errorPage和isErrorPage(发生错误的页面通过errorPage绑定跳转路径,被调用的错误页面通过isErrorPage绑定为true,实现两者的跳转)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2.include指令
用于导入页面资源,让别的页面能显示到该页面,可在body中引入
<%@ include file="/successful.jsp"%>
3.taglib指令
用于导入资源,相当于java导包
<%@ taglib prefix="c" uri="" %>
jsp内置对象
pageContext
session
request
application(servletContext)
<--不需要创建,直接调用--> pageContext.setAttribute("username","zhangsan");
MVC
model:模型层
view:视图层
controller:控制层
El表达式
格式:${表达式}
<% pageContext.setAttribute("username","zhangsan"); request.setAttribute("username","lisi"); session.setAttribute("username","wangwu"); application.setAttribute("username","zhaoliu"); %> ${pageScope.username} ${requestScope.username} ${sessionScope.username} ${applicationScope.username} <--当没有域名时,默认从作用域最小的域开始查找数据--> ${username} <--算术运算符,逻辑运算符--> ${1>1}
JSTL
1.首先在web包下创建lib包,导入jstl的jar包
创建lib包,导入jar包,点击Add as library,打开Project Structure中的Problems,解决后可以使用
2.在jsp页面中引入
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3.常用标签
<body> <% request.setAttribute("ifMarried", true); Calendar instance = Calendar.getInstance(); int i = instance.get(Calendar.DAY_OF_WEEK); request.setAttribute("weekDay",i-1); ArrayList<String> strings = new ArrayList<>(); strings.add("zhangsan"); strings.add("lisi"); request.setAttribute("items",strings); %> <%--c:if 里面的test属性必有,值为boolean值,true为显示里面内容,false不显示,一般配合el表达式使用--%> <c:if test="${ifMarried}"> xxx结婚了 </c:if> <c:if test="${!ifMarried}"> xxx没有结婚了 </c:if> <%--c:choose 相当于java中的switch语句,一般配合c:when来使用--%> <c:choose> <c:when test="${weekDay==1}">星期一</c:when> <c:when test="${weekDay==2}">星期二</c:when> <c:when test="${weekDay==3}">星期三</c:when> <c:when test="${weekDay==4}">星期四</c:when> <c:when test="${weekDay==5}">星期五</c:when> </c:choose> <%--c:forEach 相当与 for(int a = 1;a<10;a+=2){System.out.println(a);}--%> <c:forEach var="a" begin="1" end="10" step="2"> ${a} </c:forEach> <%--items内可以放置集合等可以遍历的容器,varStatus表示循环变量的状态--%> <c:forEach items="${items}" var="a" varStatus="b"> ${a}---------${b.index} </c:forEach> </body>
JSON
java script object notation
js对象的表示法,用来做网络中传输的一种格式,简洁,明了,不冗余,本质就是一串字符串
<script> // JSON对象 // 值为可以为字符串,数字,布尔值,null,js对象,js数组 let user = { "name":"zhangsan", "age":18 } // 转换成JSON字符串 let s = JSON.stringify(user); alert(s); // 取值 对象.键名 console.log(user.name); //遍历 let school = ["清华","北大","西南石油"]; for (let i = 0; i < school.length; i++) {//fori console.log(school[i]); } for (let x of school) {//forof console.log(x); } for (const x in school) {//forin console.log(school[x]); } </script>
java对象-->js对象
// 转换出来为一个js对象的json表达式 User user = new User(); user.setAge(15); user.setName("moon"); System.out.println(user); // 将java对象转换成js对象的方法 ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(user1));
//list转换为一个js数组 ArrayList<String> strings = new ArrayList<>(); strings.add("aaa"); strings.add("bbb"); strings.add("ccc"); ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(strings));
//转换出来为一个对象数组 User user1 = new User(); ArrayList<User> users = new ArrayList<>(); users.add(user); users.add(user1); ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(users));
//map转换出来为一个js对象 Map<String,String> map = new HashMap(); map.put("name","zhangsan"); map.put("age","zhangsan"); ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(map));
Ajax
优点:异步,局部刷新
同步:浏览器对服务器发送请求,在等待服务器响应的过程中,什么都不能做
异步:浏览器不需要等待服务器响应,在等待服务器响应的过程中,可以做任何事
ajax使用
1.创建jsp页面,并引入jquery(在web目录下新建static目录,并将jquery放在该目录下)
2.页面中添加事件,在事件函数中使用ajax
<body> <span>用户名:</span><input id="username" type="text" οnblur="userNameJudge()"><span id="usernameJudge"></span><br> <span>密码:</span><input id="password" type="password"><br> <button type="button" οnclick="login()">登录</button> <script> // 用于登录对账号密码的判断 function login() { var username = $("#username").val(); var password = $("#password").val(); $.ajax({ // 请求的url(旅行的目的地) url:"/ajaxServlet", // 请的方式(出行方式) type:"post", // 请求携带的参数(同行人) data:{ "username":username, "password":password }, // 返回时参数的格式 dataType:"json", // 成功回调后执行的函数 // rs接收后端传送的数据,即response.getWriter().write(string); success:function (rs) { if (rs.code == 200) { alert(rs.msg) // 账号密码正确,跳转页面 location.href="/successful.jsp" } else { alert(rs.msg) } } }) } // 用于对用户名是否可用判断 function userNameJudge() { var username = $("#username").val(); $.ajax({ url:"/usernameJudge", type:"post", data:{ "username":username, }, dataType:"json", success:function (rs) { if (rs.code == 200) { // 新增样式 $("#usernameJudge").css({'color':'green'}); // 新增内容 $("#usernameJudge").html(rs.msg); } else { $("#usernameJudge").css({'color':'red'}); $("#usernameJudge").html(rs.msg); } } }) } </script> </body>
// 账号密码判断的servlet @WebServlet("/ajaxServlet") public class AjaxServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); ResultInfo resultInfo; if ("zhangsan".equals(username)) { if ("123456".equals(password)) { // 密码正确,封装信息 resultInfo = new ResultInfo(200,"登录成功",null); } else { resultInfo = new ResultInfo(500,"密码错误",null); } } else { resultInfo = new ResultInfo(500,"账号不存在",null); } // 将封装好的信息通过json格式传递给前端 ObjectMapper objectMapper = new ObjectMapper(); String string = objectMapper.writeValueAsString(resultInfo); response.getWriter().write(string); } }
// 新建一个结果类ResultInfo public class ResultInfo { // 自己定义的状态码 private Integer code; // 响应信息 private String msg; // 响应的数据 private Object data; (有参无参构造方法) (get和set方法) (toString方法) }
Maven
概念
Maven是一个项目管理工具,它包含了一个对象模型。一组标准集合,一个依赖管理系统。和用来运行定义在生命周期阶段中插件目标和逻辑。
核心功能
Maven的核心功能是合理叙述项目间的依赖关系,通俗点就是通过pom.xml文件的配置获取jar包不用手动的去添加jar包
Maven坐标
-
groupId:Maven项目隶属的实际项目
-
artifactld:当前项目的模块名称
-
version:当前模块的版本
仓库
当maven项目需要jar包时,第一时间寻找本地仓库中的jar包,当本地仓库没有需要的jar包时,就会在中央仓库寻找,但当配置了私服时,会优先前往私服寻找,私服中没有,才会去中央仓库中寻找
maven项目结构
lifeCycle插件
1.clean
用于清除之前构建生成的所有文件
其中具体为清除Target目录中的所有文件,包括该目录
删除了install生成的所有文件
2.compile
编译项目的源代码,主要是java文件
一般是编译scr/main/java或是scr/test/java里面的文件
3.deploy
复制最终的包至远程仓库
共享给其它开发人员和项目