Java Servlet 过滤器与 springmvc 拦截器的区别?

前言:在工作中,遇到需要记录日志的情况,不知道该选择过滤器还是拦截器,故总结了一下。

servlet 过滤器

定义

  java过滤器能够对目标资源的请求和响应进行截取。过滤器的工作方式分为四种

应用场景

  可以通过 doFilter 方法的 request、response 提前过滤一些不想要的信息,统一设置一些参数、统一设置字符集、控制权限是否登录等。

配置  

  <!-- 定义Filter --><filter><!-- Filter的名字 --><filter-name>loginFilter</filter-name><!-- Filter的实现类 --><filter-class>com.yule.common.filters.LoginFilter</filter-class></filter><!-- 定义Filter拦截的URL地址 --><filter-mapping><!-- Filter的名字 --><filter-name>loginFilter</filter-name><!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求--><url-pattern>/*</url-pattern></filter-mapping>

过滤器的4种工作方式

<filter-mapping><filter-name>myFilter</filter-name><servlet-name>目标资源</servlet-name><dispatcher>REQUEST</dispatcher>
</filter-mapping>

  四中工作方式通过配置 <dispatcher> 标签来决定

  1. request 过滤器:不配 <dispatcher> 标签,或者配置为 <dispatcher>REQUEST</dispatcher> 。说明只有直接访问该目标资源时该过滤器才会起作用,对转发到该目标资源的请求将忽略不处理。
  2. forward 过滤器:配置为 <dispatcher>FORWARD</dispatcher> 。表示对转发到目标资源的请求过滤,如果直接访问目标资源,过滤器则不起作用。
  3. include 过滤器:配置为 <dispatcher>INCLUDE</dispatcher> 。表示对包含了目标资源的请求过滤,如果直接访问目标资源,则此过滤器将不起作用
    include 包含以下语句:
    在 JSP 页面中的动作:<jsp:include page=.......
    在 Java 代码中的 request.getRequestDispatcher("....").include
    注意:如果目标资源一通过 <%@ include file="目标资源二"%> 指令包含,这时此过滤器不工作,因为这个是指令,在JSP 编译时插入一个包含文本或代码的文件,这个包含的过程是静态的。
  4. error 过滤器:配置为
    <filter-mapping><filter-name>myFilter</filter-name><url-pattern>/error.jsp</url-pattern><dispatcher>ERROR</dispatcher>
    </filter-mapping><error-page><error-code>404</error-code><location>/error.jsp</location>
    </error-page>
    当我们访问一个web目标资源时,如果服务器没有找到该目标资源,那么服务器就会给出一个404错误代码。如果我们给404错误代码定义一个页面,那么当404发生时就会调用该页面。
    当我们访问一个不存在的文件时,就会访问error.jsp,但是配置了过滤器对错误页面进行过滤,所以过滤器先接受到请求,然后再转发给error.jsp。
    如果我们访问一个已经存在的页面,会不会调用error.jsp呢?如果这个页面中有response.sendError(404,"出错了!");那么该错误页面仍然会被调用,过滤器也会工作。

执行顺序

  根据 web.xml 的代码顺序来决定过滤器的执行顺序。Filter 链: 一个Web应用中,可以编写多个Filter,这些 Filter 组合起来称之为一个Filter链。

  当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法。在 doFilter 方法中,如果调用了 FilterChain 对象的 doFilter 方法,则 web 服务器会检 FilterChain 对象中是否还有 filter ,如果有,则调用第下一个 filter,如果没有,则调用目标资源。

  init() 方法和 destroy() 方法随着项目的启动和关闭才会被调用,且仅一次。

举个栗子

  web.xml 中

<!-- 定义Filter --><filter><!-- Filter的名字 --><filter-name>demoFilter</filter-name><!-- Filter的实现类 --><filter-class>com.yule.common.filters.DemoFilter</filter-class></filter><!-- 定义Filter拦截的URL地址 --><filter-mapping><!-- Filter的名字 --><filter-name>demoFilter</filter-name><!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求--><url-pattern>/*</url-pattern></filter-mapping>

  Java 代码

package com.yule.common.filters;import javax.servlet.*;
import java.io.IOException;/*** 过滤器* @author yule* @date 2018/7/2 21:52*/
public class DemoFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("demo过滤器init。。。");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("demo过滤器doFilter。。。此处省略业务处理逻辑");//通过判断是否继续往下走
        filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("demo过滤器destroy。。。");}
}

 

springmvc 拦截器

定义

  springMVC 拦截器源码解析

  Spring Web MVC的处理器拦截器。类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。拦截器是面向切面编程的,依赖的技术就是Java的动态代理。

应用场景

  1. 日志记录:记录请求日志等
  2. 权限检查:白名单等
  3. 性能监控:可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间;
  4. 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
  5. OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

  本质是AOP(面向切面编程),符合 AOP 的所有功能都可以使用拦截器实现。

配置

  在 spring-mvc.xml 中

<mvc:interceptors><!--  使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求   --><!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --><mvc:interceptor><!--进行拦截的地址--><mvc:mapping path="/**"/><bean class="com.yule.common.interceptors.DemoInterceptor"/></mvc:interceptor></mvc:interceptors>

执行顺序

  根据 xml 中的配置顺序来执行。拦截器的执行顺序在过滤器之间。

方法说明

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法,该法在请求处理之前进行调用。SpringMVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时,就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候,就会是调用当前请求的 Controller 中的方法。
  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,通过 preHandle 方法的解释咱们知道这个方法包括后面要说到的 afterCompletion 方法都只能在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 的时候,才能被调用。postHandle 方法在当前请求进行处理之后,也就是在 Controller 中的方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 是相反的,也就是说,先声明的 Interceptor 的 postHandle 方法反而会后执行。
  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,也是需要当前对应的 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。因此,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作。afterCompletion 方法被调用的方向也跟 preHandle 是相反的,也就是说,先声明的 Interceptor 的 afterCompletion 方法反而会后执行

举个栗子

  spring-mvc 中

<mvc:interceptors><!--  使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求   --><!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --><mvc:interceptor><!--进行拦截的地址--><mvc:mapping path="/**"/><bean class="com.yule.common.interceptors.DemoInterceptor"/></mvc:interceptor></mvc:interceptors>

  Java 代码

package com.yule.common.interceptors;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 自定义拦截器方式一* Created by yule on 2018/7/2 22:37.*/
public class DemoInterceptor implements HandlerInterceptor{@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {//return true 表示继续下一个拦截器或者 control 层//return false 表示被拦截下来return false;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
}
package com.yule.common.interceptors;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 自定义拦截器方式二* 一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理* Created by yule on 2018/7/2 22:43.*/
public class Demo2Interceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}
}

 区别

  其实两者还是有相似之处,就是都可以用作权限检查、日志记录等情况,但是在这些情况下如何选择就要知道不同之处。

不同之处

  使用范围不同:Filter 只能用于 Web 程序中。而拦截器可以用于 Web 程序,Application、Swing 程序中。

  规范不同:Filter 是 servlet 规范规定的,是 servlet 支持的。而拦截器是在 spring 容器内,是 spring 框架支持的。

  使用资源不同:Filter 不能直接使用 spring 的资源、对象等。而拦截器是一个 spring 组件,归 spring 管理,配置在 spring 文件中,因此能使用 spring 的任何资源、对象,例如 Service 对象、数据源、事务管理等,通过 IoC 注入到拦截器即可。也就是说在拦截器中可以注入一个 service ,用于业务逻辑或者访问数据库。

  深度不同:Filter 只在 Servlet 前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。

  作用范围不同:拦截器只能对 Controller 层请求起作用,而过滤器则可以对几乎所有的请求起作用(如 .js、.css等)。

  所以,在 Spring 构架的程序中,要优先使用拦截器。

注意

  拦截器是在过滤器之间运行的。

执行顺序举例

拦截器,spring-mvc.xml 中:

<mvc:interceptors><!--  使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求   --><!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --><mvc:interceptor><!--进行拦截的地址--><mvc:mapping path="/**"/><bean class="com.yule.common.interceptors.DemoInterceptor"/></mvc:interceptor><mvc:interceptor><!--进行拦截的地址--><mvc:mapping path="/**"/><bean class="com.yule.common.interceptors.Demo2Interceptor"/></mvc:interceptor></mvc:interceptors>

java 代码:

package com.yule.common.interceptors;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 自定义拦截器方式一* Created by yule on 2018/7/2 22:37.*/
public class DemoInterceptor implements HandlerInterceptor{@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {//return true 表示继续下一个拦截器或者 control 层//return false 表示被拦截下来System.out.println("preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {System.out.println("postHandle");}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {System.out.println("afterCompletion");}
}
View Code
package com.yule.common.interceptors;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 自定义拦截器方式二* 一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理* Created by yule on 2018/7/2 22:43.*/
public class Demo2Interceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle 2222222...");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle 22222222");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion 2222222");}
}
View Code

过滤器, web.xml 中:

<!-- 定义Filter --><filter><!-- Filter的名字 --><filter-name>demoFilter</filter-name><!-- Filter的实现类 --><filter-class>com.yule.common.filters.DemoFilter</filter-class></filter><!-- 定义Filter拦截的URL地址 --><filter-mapping><!-- Filter的名字 --><filter-name>demoFilter</filter-name><!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求--><url-pattern>/*</url-pattern></filter-mapping><filter><filter-name>demo2Filter</filter-name><filter-class>com.yule.common.filters.Demo2Filter</filter-class></filter><filter-mapping><filter-name>demo2Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

java 代码:

package com.yule.common.filters;import javax.servlet.*;
import java.io.IOException;/*** 过滤器* @author yule* @date 2018/7/2 21:52*/
public class DemoFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("demo过滤器init。。。");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("demo过滤器doFilter。。。此处省略业务处理逻辑");//通过判断是否继续往下走
        filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("demo过滤器destroy。。。");}
}
View Code
package com.yule.common.filters;import javax.servlet.*;
import java.io.IOException;/*** Created by yule on 2018/7/2 22:18.*/
public class Demo2Filter implements Filter{@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("demo2过滤器init  2222222");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("demo过滤器doFilter  222222");//通过判断是否继续往下走
        filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("demo2过滤器destroy  22222 ");}
}
View Code

调用 controller 打印结果:

 

转载于:https://www.cnblogs.com/yuxiaole/p/9230742.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/427526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

surface pro 6 黑苹果_微软Surface新款超薄触控笔抢鲜评测

微软Surface新款超薄触控笔抢鲜评测中文名&#xff1a;微软 Surface 超薄触控笔英文名&#xff1a;Surface Slim Pen日文名&#xff1a;Surface スリム ペン颜色&#xff1a;典雅黑&#xff08;只有这一个颜色&#xff09;中文官方链接&#xff1a;https://www.microsoftstore.…

C++ function bind以及lamda表达式

本文是C0x系列的第四篇&#xff0c;主要是内容是C0x中新增的lambda表达式, function对象和bind机制。之所以把这三块放在一起讲&#xff0c;是因为这三块之间有着非常密切的关系&#xff0c;通过对比学习&#xff0c;加深对这部分内容的理解。在开始之间&#xff0c;首先要讲一…

java轻松实现无锁队列

1、什么是无锁(Lock-Free)编程 当谈及 Lock-Free 编程时&#xff0c;我们常将其概念与 Mutex(互斥) 或 Lock(锁) 联系在一起&#xff0c;描述要在编程中尽量少使用这些锁结构&#xff0c;降低线程间互相阻塞的机会&#xff0c;以提高应用程序的性能。类同的概念还有 "Lock…

numpy数组按某一维度相加_Python数据分析之NumPy(高级篇)

​一些更高级的ndarray处理where和一些其他的逻辑运算np.where(cond,x,y)&#xff1a;满足条件(cond)输出x&#xff0c;不满足输出yx_arr np.array([1.1, 1.2, 1.3, 1.4, 1.5])y_arr np.array([2.1, 2.2, 2.3, 2.4, 2.5])cond np.array([True, False, True, True, False])pr…

Python入门:局部变量与全局变量2

例子1&#xff1a; names("Lili","Rain","Jack") change_name(name): names[0]"LiLy" print(names) 结果&#xff1a;names("LiLy","Rain","Jack") #列表可以在函数中直接修改 例子2&#xff1a; name…

md5与des算法有何不同_到底AI芯片和传统芯片有何区别?

前两天成立仅两年国内专做人工智能FPGA加速算法的初创公司深鉴科技被国际巨头赛灵思收购了&#xff0c;在业界引起不小的震动。目前国内做AI芯片的公司可谓不少了&#xff0c;AI芯片已然成为了当下芯片行业最热领域。但是大部分人对AI芯片的架构应该都不是太了解。那么AI 芯片和…

BlueTooth 蓝牙音频音质探讨

蓝牙音频音质探讨简介&#xff1a;本文简单介绍了蓝牙无线音频技术 A2DP&#xff0c;并从技术角度探讨其音质。1. 蓝牙 A2DP 简介我们先从蓝牙核心规范说起&#xff0c;目前支持最广泛的蓝牙 2.0/2.1 EDR 连接速率为 3Mbit/s&#xff0c;实际可用数据传输速率为 2.1Mbit/s。蓝…

Active Directory PowerShell模块收集AD信息

0x00 前言简介 Microsoft为Windows Server 2008 R2&#xff08;以及更高版本&#xff09;提供了多个Active Directory PowerShell cmdlet&#xff0c;这大大简化了以前需要将涉及到的ADSI冗长代码行放在一起的任务。 在Windows客户端上&#xff0c;需要安装远程服务器管理工具&…

anaconda对应python版本_Python基础——如何查看python版本、如何查看多个python版本

前言初学者来说&#xff0c;安装python过程是存在一定难度的。在安装过程中&#xff0c;可能安装了多个python版本&#xff0c;可能安装了anaconda导致有自带的python&#xff0c;同时本身电脑也安装了官方下载的python也茫然不知。导致可能有以下情况发生&#xff1a;1.pip in…

MATLAB统计与回归

11.1 前言統計的技巧與資料分析常常形影不離。一般統計使用加法、累加法、平均值&#xff0c;中間值等等&#xff0c;由於處理的對象是矩陣資料&#xff0c;故其基本統計之技巧已經廣為應用&#xff0c;其觀念也會在正常之運作中出現。統計學中比較特殊應用者為機率、亂數、常態…

如何快速理解读懂他人代码(下)——技巧学习篇

四、望文生义&#xff0c;进而推敲组件的作用 先建立系统的架构性认识&#xff0c;然后透过名称及命名惯例&#xff0c;就可以推测出各组件的作用。例如&#xff1a;当Winamp尝试着初始化一个Plug-In时&#xff0c;它会呼叫这个结构 中的init函式&#xff0c;以便让每个Plug-I…

yii2通过url访问类中的方法_每日学点---nginx变量使用方法详解(3)

也有一些内建变量是支持改写的&#xff0c;其中一个例子是 $args. 这个变量在读取时返回当前请求的 URL 参数串(即请求 URL 中问号后面的部分&#xff0c;如果有的话 )&#xff0c;而在赋值时可以直接修改参数串。我们来看一个例子&#xff1a;location /test { set $orig_args…

GOOGLE HACKING 系列文章 【FreeXploiT整理收集】

本文涉及作者 swap&#xff08;慕容小雨&#xff09;&#xff0c;zhaohuan&#xff08;Xfocus&#xff09;&#xff0c;snipe&#xff08;4ngel&#xff09;信息安全的隐患-GoogleHacking原理和防范作者&#xff1a;zhaohuanphack.org 来源&#xff1a;www.phack.org技术天地&a…

Openldap命令详解

Openldap 客户端常用管理命令 1、ldapadd -x: 简答认证方式-W: 不需要在命令上写密码 ldapapp -x -D "cnManager,dcsuixingpay,dccom" -W-w: password 需要命令上指定密码 ldapapp -x -D "cnManager,dcsuixingpay,dccom" -w 123456-H: 通过ldapapi-h: host…

用python画六瓣雪花_python-turtle-画雪花-2种方法及效果的详解

#python3.8#xuguojun#2020.1.30#导出模块&#xff0c;这样导出比代码较简洁&#xff0c;但是注意r和后面RGB的r&#xff0c;所以我改为d代替R&#xff08;r&#xff09; importturtle as timportrandom as r#绘制雪花 s30 #定义30个 defsnow(s): t.ht()#hthideturtle&#xff0…

2018年高考游记

2018年高考游记 在前言之前&#xff1a; 这篇文章已经写十几天吧 有心情时偶尔写上几段 也不知道自己抱着什么心态了&#xff0c;是留下一点回忆&#xff0c;还是给看得人启迪&#xff0c;还是...... 反正是要写出点东西来的 凡是现实的都是合乎理性的&#xff0c;凡是合乎理性…

小白学python需要多久_小白学Python | 你还在说你入不了门吗

收藏的好多啊 原创不易&#xff0c;动动小手&#xff0c;点个赞啦&#xff01;&#xff01; 十二月份&#xff0c;天气有时候会很阴沉&#xff0c;一天都见不到太阳。气温也慢慢变冷了&#xff0c;晚上回家还是会感觉到衣服穿少了。 阴阴沉沉总会过去的&#xff0c;我还是期待阳…

欧美剧集观看最佳索引 【2006-9-24更新】

allyesno&#xff1a;我在上两个月说要做一个美剧的网站 由于最近公司的事情一直很繁忙 我没有时间去做自己都积累了一大堆 美剧 日剧 恐怖片 没看 两个电脑的硬盘都塞的满满的 呵呵真是 天长地久有时尽,此恨绵绵无绝期。 哈哈~ 我现在正在构思 是不是把美剧网站列入公司的发展…

python语言format用法_详解Python中的format格式化函数的使用方法

format函数实现字符串格式化的功能 基本语法为&#xff1a; 通过 : 和 {} 来控制字符串的操作 一、对字符串进行操作 1. 不设置指定位置&#xff0c;按默认顺序插入 ①当参数个数等于{}个数的时候 str_1 "小明{}小美,可是小美{}小明".format("喜欢", &quo…

如何提高英文的科研写作能力

作为一个科研工作者&#xff0c;在国际学术期刊上发表科研论文是与同行交流、取得国际影响的必经之路。有些国内的科学家&#xff0c;实验做得很漂亮&#xff0c;但常常苦恼于论文的写作力不从心&#xff0c;成为国际交流的一大障碍。本文从博主的亲身体验出发&#xff0c;给博…