16340005 蔡俊琪 技术与工作报告
学习将近一个月半,从Spring开始一路学来,作此文来一个大概的回顾。
HTTP
HTTP又名超文本传输协议,是我们在互联网中使用最广泛的传输协议。HTTP基于TCP/IP实现,其流程如下
TCP
TCP是经常会问到的知识点,如三次握手和四次挥手、ack和req字段:
对于tcp来说,建立连接需要发送方和接收方依次发送一个SYN位为1的数据包给对方,都接收到之后发送方再更新请求字段ACK,开始数据传输,其交流过程以seq和ack为依据:
通俗说,ack值表示对方字节流内希望接到的第一个字节位置。seq值表示己方字节流内准备发送的第一个字节位置
seq和ack构成了一种安全的同步机制,假设在丢包情况下无限制重传,只要对方发来的seq不等于我发的ack,我就知道上一个包丢失了,继续重发,直到发来的seq推进了。
假设上图B发的包6丢了,由于超时A会重传包4,这时候B发现,包4的seq字段不等于B的ack字段,显然如果包6没丢,A接收到包6后会根据包6的ack字段更新自己的seq字段(表示A知道B已经收到了)。如果发生丢包,B知道自己收到了包4,但是A不知道,那原因就是B用来告诉A的包6丢了。
四次挥手就是两次各自用FIN=1来通知对方自己不再发送数据(不是再也不重传或者不发送确认回执,只是不会再去发送新的程序数据了),对方发送一次确认回执,总共四次。
IP协议帮助我们在网络间正确分发传输数据包,tcp协议帮助我们构建一个抽象的连接,并将数据包分发到正确的进程上。而最后的HTTP协议则帮我们设置了一种交流格式,通过这种格式我们能有效地进行大部分web相关的信息交流。
具体格式见https://www.cnblogs.com/whgk/p/6130882.html
Servlet
现在我们知道如何通过一个HTTP协议进行计算机之间的访问,还要知道如何对这种访问进行处理。
init():初始化
service():对发来的HTTP访问进行解析(分发)
destory():终止
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
一般来说,如果直接通过实现Servlet接口的HttpServlet进行编程,我们要自己去获取ServletRequest和ServletResponse,但是如果使用一个Servlet容器(比如Tomcat),这个就会自动装配好。
基本上来说,上面三个函数都不需要我们自己实现(GenerticServlet帮我们封装了ServletConfig以及一个可以重写的init接口),我们需要重写的方法包括doXXX(如doGet、doPost,httpServlet实现了service方法,留下do方法给我们实现),来对GET和POST请求做具体的处理。
通过获取request里的参数进行业务逻辑处理,再将结果放入response中,就可以正确响应一个HTTP请求了
web.xml:
这个配置文件用来说明如何将一个访问映射到不同servlet上。
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
也就是说,把http://localhost:8080/HelloWorld这个访问URL分发(映射)给HelloWorld这个servlet类处理。
过滤器:
用来做一个预处理或者后处理
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.w3cschool.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>w3cschool在线教程</param-value>
</init-param>
</filter>
在web.xml里面做个映射
在实现Filter接口的过滤器类里面做具体操作
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws java.io.IOException, ServletException {
// 获取客户机的 IP 地址
String ipAddress = request.getRemoteAddr();
// 记录 IP 地址和当前时间戳
System.out.println("IP "+ ipAddress + ", Time "
+ new Date().toString());
// 把请求传回过滤链
chain.doFilter(request,response);
}
注意chain.doFilter回调
多个过滤器的执行顺序和在xml里面声明的顺序是一样的
Servlet容器
容器包括Tomcat、Jboss、Jetty。可以帮助我们管理servlet。
MVC
如果我们只使用最基本的HttpServlet,那么Servlet就承担了所有工作:既要处理请求(业务逻辑),又要获取数据(数据库),最后还要返回一个视图(html)。
MVC模式建议把这三个工作分离开来各司其职,据此实现的开源框架有:SpringMVC、Struts+
SpringMVC
web.xml
为了使用springmvc,我们要把url映射到DispatcherServlet,也就是Spring提供的一个Servlet分发类,该类根据ServerAndDB(xml里的标识名)-servlet.xml中的配置将不同url请求进一步分发到控制器的不同方法内进行处理。
控制器(Controller)
说直白点,控制器编写业务逻辑(根据参数要去干些啥)
这里我们用了注解进行开发,因为确实很方便,只需要在ServerAndDB-servlet.xml中配置一句
就可以愉快开发了。
必须的注解是@Controller:告诉分发类可以来这找对应的处理器、@RequestMapping:用value告诉分发类该方法处理的url,
可选:method是一个限定,默认post和get都能处理的。@ResponseBody是说返回一个String、Map、JSON这种非网页的数据。
@RequestParam是将请求url里的参数名进行映射,如果请求参数名和形参名一直就不需要,比如上图就是冗余的
视图(View)
xxx-sevlet.xml
controller
声明InternalResourceViewResolver自动帮我们解析jsp视图,prefix、suffix声明前后缀。
直接在return返回jsp文件或者在ModelAndView里面setViewName即可完成View部分
Struts
web.xml
这里是用filter而不是servlet标签,也就是说,把请求放到Struts提供的StrutsPrepareAndExecuteFilter这个过滤类分发。
struts.xml
在struts.xml里面action标签:name:就是url class:就是处理器类 method:就是要调用处理器里的哪个方法。一般默认是execute,也可以自己指定。
interceptor是拦截器,其实也是预处理,struts有默认的defaultStack帮我们实现了很多有用的拦截器,一般来说不需要显式配置,但是要用别的拦截器的话,最好再声明一下。result是根据处理器return的字符串来选择返回的jsp页面
struts的处理器叫做action,可以选择不实现action接口,也可以实现,或者直接继承ActionSupport类。
实现ModelDriven<String>接口,实现getModel(),这个函数返回的object会被放到栈顶自动装配。但其实defaultStack的拦截器已经帮我们做好了参数拦截。只要我们在jsp或者url里面的参数名一致就行了。
Model
Model就是数据层,最基础的访问方式就是jdbc,spring有提供jdbcTemplate,比较成熟的框架有Hibernate、Mybatis
jdbc就不说了,基本都是用preparedStatement
jdbcTemplate
要给template一个数据源,在mySpring.xml中配置
因为autowired了,就没必要在xml里面依赖注入
使用基本就是update,execute用来执行DDL,update用来做增删改,query用来做查,queryForObject只能返回一行,如果有多行或者没有行,就会报错。
这个时间戳用来存储时间,能精确到时分秒。使用Date那些就只能精确到天。
这里的查询返回一个集合,需要提供一个Mapper用于映射
来帮我们从表项转换到一个对象。
这里就看出来用jdbcTemplate的麻烦之处了,不仅要写一个Task类,还要写个映射类。多个实体类就要多个映射类,管理起来很麻烦。
Hibernate
Hibernate帮我们专注于操作对象,同样一个操作,在jdbcTemplate里面是这样的
可以看到,我们需要知道底层的Task数据库有一个tid字段。可是在Hibernate就不一样了。
注意 user.name ,这里的name不是表字段,而是User这个java类的字段,所以我们编程的时候就不用管底层是啥玩意儿了,当然了,我们得为此做一些配置
User.hbm.xml
可以看到,这里相当于一个mapper类,但是我们写一个类就只是一个类,而这一个User.hbm.xml能写很多个mapper标签,就方便我们管理映射了。主要就是声明实体类、表名、主键、其他字段
hibernate.cfg.xml
这个xml大概和spring配置差不多,就是多个mapping标签指示我们管理映射的xml文件在哪
实体类要写一个空的User构造器
查询
先开启连接、开启事务
HQL:就是上面介绍过的面向对象的一种查询
下面使用了命名参数,其实就类似于preparedStatement里的?占位符,只不过这里有自己的名字,可以按任意顺序直接赋值,而?占位符必须按顺序填参数
但是HQL不能直接插入,要插入如下图
总的来说Hibernate能更好地管理表到实体类的映射,而且能以我们OOP的思维去写HQL,确实比较方便。
Mybatis