接:Servlet的日常开发(基于场景)_林纾໌້ᮨ的博客-CSDN博客
目录
一、模板技术
二、前后端分离
总结—图析:
三、Java中为什么需要这么多类
1.承载数据的对象
2.承载流程的对象
对上面代码重构,分一下包:
四、浏览器以JSON格式把数据给服务器
1)通过JSON方式发送一个请求体
2)从请求体中把数据读出
五、eg:在浏览器中看到一个页面的简单架构
观察上个博客中的代码可知,拼接HTML是比较麻烦的(都是字符串操作),需要手写写出所有字符串,可以有两种技术来改善:
1.模板技术(jsp、thymeleaf...)
2.前后端分离(后端只负责提供数据,以JSON格式,前端JS修改DOM树)
一、模板技术
提前把HTML的内容放在一个文件中
模板
你好 {{ target }}
//Template:模板
//模板模式:提前写好一个文件(template.html)作为模板
public class WithTemplate {
public static void main(String[] args) throws IOException {
try(FileInputStream is=new FileInputStream("template.html")){
try(Reader reader=new InputStreamReader(is,"UTF-8")){
char[] buf=new char[1024];
int n=reader.read(buf);
String template=new String(buf,0,n);
String s=template.replace("{{ target }}","世界");
System.out.println(s);
}
}
}
}
二、前后端分离
前端通过ajax技术,从后端(通过HTTP协议)读取数据(数据的格式是JSON为主)
eg:对录入成绩前后端分离
静态资源:
成绩列表
@WebServlet("/grade-list.json")
public class GradeListJsonServlet extends HttpServlet {
private final HashMap gradeMap=new HashMap<>();
//初始化
@Override
public void init() throws ServletException {
gradeMap.put("小A",100);
gradeMap.put("小B",90);
gradeMap.put("小C",80);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//输出:json格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");//json格式的输出
PrintWriter writer = resp.getWriter();//把小A...这组数据类似拼接成开心超人那些属性那样的格式
//调用getJSON方法进行拼接操作
String json=getJSON();
writer.println(json);
}
//手动写拼接方法
private String getJSON() {
StringBuilder sb=new StringBuilder();
sb.append("[");
for (Map.Entry entry: gradeMap.entrySet()) {
String name= entry.getKey();
int value=entry.getValue();
sb.append("{")
.append(""姓名": ")
.append(""")
.append(name)
.append("",")
.append(""成绩": ")
.append(value)
.append("},");
}
sb.delete(sb.length()-1,sb.length());
sb.append("]");
return sb.toString();
}
}
上面改动态资源是用拼接json格式自己拼接的,比较麻烦,可以引用别人提供好的方法去做:引入一个第三方包:
com.fasterxml.jackson.core jackson-databind2.12.4
@WebServlet("/grade-list.json")
public class GradeListJsonServlet extends HttpServlet {
// private final HashMap gradeMap=new HashMap<>();
List
小结:index.html通过构建ajax GET(用户直接GET)请求动态资源/grade-list.json,动态资源根据数据修改DOM树(将index.html内容按所想要的方式呈现)
继续改造:
对象和Map其实是一回事,JSON直接支持定义好一个类往里面放东西,所以可以:
class Grade{
姓名;
成绩;
}
List
public class Grade {
public String 姓名;
public int 成绩;
}
@WebServlet("/grade-list.json")
public class GradeListJsonServlet extends HttpServlet {
// private final HashMap gradeMap=new HashMap<>();
List
问题:一般java中不直接用中文起名,如Grade类中的姓名成绩,一般用英文起名,但是修改代码会出问题,即你在Grade修改成英文时,访问grade-list.json显示修改成功,但是调用index显示是错误显示的(因为html中写的是姓名成绩两个中文)。
解决:通过注解的方式
此时数据全部处理OK,可以将数据改到数据库中(利用之前数据库grades表,直接在数据库中查询),此时代码:
public class GetGradeList {
List list=new ArrayList<>();
public List getList(){
try (Connection c= DBUtil.connection()){
String sql="select name,grade from grades order by id";
try(PreparedStatement ps=c.prepareStatement(sql)){
try (ResultSet rs= ps.executeQuery()){
while (rs.next()){
Grade grade=new Grade();
grade.name=rs.getString("name");
grade.score=rs.getInt("grade");
list.add(grade);
}
}
}
}catch (SQLException e){
throw new RuntimeException(e);
}
return list;
}
}
@WebServlet("/grade-list.json")
public class GradeListJsonServlet extends HttpServlet {
//初始化GetGradeList类:(该类负责从数据库中查出数据并放在了该类的list中返回)
private final GetGradeList getGradeList=new GetGradeList();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//输出:json格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");//json格式的输出
PrintWriter writer = resp.getWriter();//把小A...这组数据类似拼接成开心超人那些属性那样的格式
//调用getJSON方法进行拼接操作
String json=getJSON();
writer.println(json);
}
//调用别人写好的东西
//将数据来源改为从数据库拿(与其他没有差别,只是这里数据源出现区别,变成了数据库中读到的数据)
private String getJSON() {
ObjectMapper om=new ObjectMapper();
try{
List list=getGradeList.getList();//获取GetGradeList类的对象getGradeList调用到的数据(name,score)给list
return om.writerWithDefaultPrettyPrinter().writeValueAsString(list);//将数据序列化(调用别人写好的方法将数据转化为了对应的json格式)
}catch (JsonProcessingException e){
throw new RuntimeException(e);
}
}
}
总结—图析:
三、Java中为什么需要这么多类
java中一切皆对象,可分成两种:
1.承载数据的对象
eg:宫保鸡丁、鱼香肉丝、麻婆豆腐:是加工出来的产品
承载数据重要的是属性,如上面Grade类,类中只有属性name score,完全无方法,这就是承载数据的对象,以数据位主。
| 数据承担的是各种各样的序列化 | 如上面代码json格式的序列化 |
| 数据为什么序列化 | 序列化的目标是存储和搬运(酒厂中的酒才需要搬运,厂房不要) |
| 一般承载数据的对象中的方法 | equals、comparable、hashCode(产品间才有比较的价值) |
2.承载流程的对象
eg:前台、服务员、厨师:流程,是职责中的一部分
承载流程重要的是方法,如上面代码GetGradeList和GradeListJsonServlet就是流程,GetGradeList就是从数据库中把对象查出来这个过程,就是个流程/方法。
总而言之,实际开发中,有偏向数据的对象,有偏向属性的对象,一般也没有纯数据或纯方法,讲求一个偏向性来理解。
一般使用流程时主要是单例的
1)MVC:Model(模型-厨师)+View(展示)+Controller(控制器)
2)Controller(前台)+Service(服务员)+DataAccessObject(数据访问对象DAO(厨师))
Controller负责承接HTTP,即对接过来的客户点什么菜,DAO,即dao对象,库管,从数据库(仓库)里面把东西拿出来,Service上面代码无,我们流程简单,只是拿出来就给前台了,若业务复杂,就需要服务员参与。
对上面代码重构,分一下包:
GetGradeList放在dao层/包下,改名GradeDao,可以给看的人快速知道这是从数据库取东西的一个类,数据放在model层下,model包下放承载数据职责的类,util包下放DBUtil工具。
Model类型对象也被称为DataObject(DO),注意不要和DAO混起来。
四、浏览器以JSON格式把数据给服务器
之前代码是服务器以json格式把数据给浏览器,浏览器以表单(form)形式将数据交给服务器,但还可以以json方式发送过去,如下:
1)通过JSON方式发送一个请求体
只做json数据的发送,即浏览器以json形式把数据发给服务器
分析:students和json之间是相互转化的,String(JSON下的/JSON格式)到数据(json格式解析后的内容)是在JS中调的是JSON.parse(...),叫做解序列化过程,数据到String,在JS中是JSON.stringify(...),叫做序列化过程。(数据->String在java中用ObjectMapper.writeValueAsString(...),String->数据在java中用ObjectMapper.readValue(...))
2)从请求体中把数据读出
package com.wy4.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wy4.model.Grade;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@WebServlet("/get-json-from-request-body")
public class GetJsonFromRequestBodyServlet extends HttpServlet {
//支持的方法是POST方法,因为是POST请求提交的
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.请求体放在req.getInputStream()的输入流中
InputStream inputStream = req.getInputStream();
//2.利用Jackson进行解析(这个需要导依赖)
ObjectMapper om=new ObjectMapper();
//3.3
List list = om.readValue(inputStream, om.getTypeFactory().constructParametricType(List.class, Grade.class));
for (Grade grade:list) {
System.out.println(grade);
}
//结果:Grade{name='小赵', score=83}
//Grade{name='小钱', score=84}
//Grade{name='小李', score=85}
// //3.2. 读一行
// List list1 = om.readValue(inputStream, List.class);//数据里主要是List.class。至于外面的list会自己帮我解析,最终就会解析出来
//写的话操作是write,在GradeListJsonServlet类里有
// //结果:[{姓名=小赵, 成绩=83}, {姓名=小钱, 成绩=84}, {姓名=小李, 成绩=85}]
// System.out.println(list1);
// //3.1.多个读
// Object o = om.readValue(inputStream, om.getTypeFactory().constructParametricType(List.class, Grade.class));
// System.out.println(o);
//结果:[Grade{name='小赵', score=83}, Grade{name='小钱', score=84}, Grade{name='小李', score=85}]
}
}
public class Grade {
//注解意思是写到json里面是用姓名or成绩作为它的key
@JsonProperty("姓名")
public String name;
@JsonProperty("成绩")
public int score;
@Override
public String toString() {
return "Grade{" +
"name='" + name + ''' +
", score=" + score +
'}';
}
}
五、eg:在浏览器中看到一个页面的简单架构
public class Grade {
//注解意思是写到json里面是用姓名or成绩作为它的key
@JsonProperty("姓名")
public String name;
@JsonProperty("成绩")
public int score;
@Override
public String toString() {
return "Grade{" +
"name='" + name + ''' +
", score=" + score +
'}';
}
}
在前后端分离的场景下:
xxx.html是用户看到的主页面,是入口。页面由多个资源组成,一般就是css做样式资源,js做逻辑资源,除此之外,在前后端分离场景下,数据往往是后端以xxx.json形式提供好的。
eg:其他代码小练习:
成绩列表
@WebServlet("/save.json")
public class SaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper om=new ObjectMapper();
Grade grade=om.readValue(req.getInputStream(),Grade.class);
System.out.println(grade);
//TODO:保存到数据库中
try(Connection c= DBUtil.connection()){
String sql="insert into grades(name,grade) values(?,?)";
try(PreparedStatement ps=c.prepareStatement(sql)){
ps.setString(1,grade.name);
ps.setInt(2,grade.score);
ps.executeUpdate();
}
}catch (SQLException e){
throw new RuntimeException(e);
}
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");
PrintWriter writer = resp.getWriter();
HashMap result=new HashMap<>();
result.put("结果","正确");
String s=om.writeValueAsString(result);
writer.println(s);
}
}



