后端问题
1.@Controller和@Conponent的区别
- 通常情况下我们认为二者没有太大的区别,两个注解都会使得被注解的类被加载到Spring容器中,被IOC容器管理;
- @Controller继承了@Conponent,具有@Conponent的功能,
- @Controller主要用于标记控制器类,它通常在SpringMVC应用程序中使用,用于处理Web请求和返回视图或数据;
- @Conponent是通用的Spring容器管理组件的注解,可以用于标记任何普通类,不仅限于控制器;
-
- @Controller注解的类通常包含处理HTTP请求的方法,可以利用@RequestMapping或其他相关注解来定义请求映射和处理逻辑;
- @Conponent注解的类通常是通用的Spring Bean,用于在应用程序中提供各种功能;
-
@Controller
注解通常是Spring MVC框架中的一部分,Spring MVC会自动扫描并注册标记有@Controller
注解的类。@Component
注解也会被Spring自动扫描,但它用于通用的Spring IoC容器管理,因此它的范围更广。
2.路径问题
- 访问报404,先检查路径是否有打错字; 其次,检查是否需要加上上下文路径; 再者,检查前后端参数名字是否对应.
- 是否忘记添加了注解,是否开启了包扫描,是否被过滤器过滤了;
- @RequestBody如果接收对象在参数前面加一个
3.@RestController和return问题
新理解:
@RestController
是Spring MVC中的一个特殊注解,通常用于构建RESTful Web服务。@RestController
注解告诉Spring该控制器的每个方法都应该将方法的返回值直接作为HTTP响应的主体,而不是视图路径。
- 默认会经过视图解析器进行解析, 如果返回前加了forward: 或redirect: + /… 这时不会经过视图解析器, 进入对应的路径映射;
- 其他是返回对应的视图, 一般需要加后缀.html等, 一般我们会配置theamleaf等模板, 自动解析加前缀后缀等, 如果没有加可以手动配置一下;
- @RestController是@controller和@ResponseBody的组合注解, 这样可以返回字符串JSON格式;使用@RestController或@ResponseBody不会走视图解析器, 会将返回当做字符串或对象以JSON格式返回到前端页面
- @RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直接填入 HTTP 响应体中,是 REST 风格的控制器。
- 单独使用 @Controller 不加 @ResponseBody的话一般是用在要返回一个视图的情况,这种情况属于比较传统的 Spring MVC 的应用,对应于前后端不分离的情况。@Controller +@ResponseBody 返回 JSON 或 XML 形式数据
- 这里涉及到Restful风格, 地址不改变, 通过改变不同的提交方式GET, POST等会调用不同的方法, 隐藏细节@GetMapping, @PostMapping, @PutMapping, @DeleteMapping…
- 需要使用@RestController注解, 或者@Controller + @ResponseBody
@RequestBody
新姿势:
-
@RequestBody
注解通常用于处理包含请求体数据的 HTTP 请求,而不是 GET 请求,GET 请求通常使用
@RequestParam` 来获取 URL 查询参数 -
@RequestBody
用于标识方法参数应该绑定到HTTP请求的请求体(Request Body)部分。它通常与处理HTTP POST或PUT请求一起使用,以从请求体中提取数据并将其映射到方法参数上 -
当你在方法参数上使用
@RequestBody
注解时,Spring MVC会尝试从请求体中提取数据,并将其转换为方法参数所指定的类型。通常,这用于处理POST请求,其中请求体包含了要传递的数据,通常是JSON或XML格式的数据。 -
使用场景: 使用RESTful API时, 接收 JSON 或 XML 数据, 处理复杂的数据对象
-
当你不使用
@RequestBody
注解时,Spring MVC会从请求的各个部分(如查询参数、表单字段等)中提取数据,并将其绑定到方法参数。通常,这用于处理GET请求或表单提交等情况。例如, 传统的表单提交, 接收来自请求URL、查询参数或表单字段等的数据。
查询参数:当你需要从URL中提取查询参数时,通常使用@RequestParam
注解而不是@RequestBody
。
4.@Autowired和@Resource获取Bean
- @Autowired是按类型查找对应的Bean,如果有多个Bean同类型则加上@Qualifier指定要注入的Bean的名称
- @Resource按指定的条件查找,默认是按名字查找对应的Bean
- 推荐使用@Autowired, 在一些没有使用Spring框架的情况下使用@Resource
字段注入、构造函数注入、Setter方法注入
这是注入别的类的方式, 不是注入Spring容器而是已经存在于Spring容器了
-
字段注入虽然代码更加简洁, 但不够健壮, 会导致一些问题, 例如难以测试和难以定位依赖性问题;
@Autowired private LoginInterceptor loginInterceptor;
-
构造函数注入(推荐方式), 更容易测试, 页更有助于实现依赖项注入的不可变性;
private LoginInterceptor loginInterceptor; // 需要提供带参构造 @Autowired public WebMvcConfig(LoginInterceptor loginInterceptor){ this.loginInterceptor = loginInterceptor; }
-
Setter方法注入, 字段注入容易导致循环依赖,而构造函数注入则能够避免这个问题
private LoginInterceptor loginInterceptor; // Setter方法注入依赖 @Autowired public setLoginInterceptor(LoginInterceptor loginInterceptor){ this.loginInterceptor = loginInterceptor; }
Bean属性注入
- xml配置的方式需要setter方法
- 注解方式不需要setter方法, 通过反射机制来注入属性的值
前端问题
var和let
作用域:
var
:在函数作用域内声明变量,即它的作用范围限于包含它的函数。如果在函数内部声明的,那么它在整个函数内都可见。let
:在块级作用域内声明变量,它的作用范围限于包含它的块(通常是一对花括号{}
)。这意味着它不会像var
那样污染整个函数作用域。
变量提升:
var
:在变量声明之前可以访问变量,但它的值为undefined
。这是因为var
变量会被提升到作用域的顶部。let
:let
声明的变量不会在声明之前访问,它们不会被提升。如果你在声明之前访问let
变量,会得到一个ReferenceError
。
重复声明:
var
:允许重复声明同一变量,不会引发错误。let
:不允许在同一作用域内重复声明同名变量,会引发错误。
全局对象属性:
var
声明的变量会成为全局对象的属性,例如在浏览器环境中,window
对象。let
声明的变量不会成为全局对象的属性,它们只存在于声明它们的块或函数的作用域内。
由于
let
有块级作用域,它更安全且通常更可预测。因此,建议在现代 JavaScript 中使用let
来声明变量,特别是在需要块级作用域的情况下。而var
主要用于兼容旧版浏览器或在某些特殊情况下
MVC拦截器小记
一些新的理解:
preHandle返回true才是可以继续向前执行, 返回false应该进行重定向
- 首先, 在配置类里配置哪些应该被拦截, 哪些应该被放行(一些静态资源,登录页面和错误页面等); 在拦截器类里实现被拦截的具体逻辑, 以及被拦截后重定向到哪
- 样式被拦截是因为静态资源CSS等被拦截了,(如果是配置了 “/**” 拦截所有) 应该单独放行 ps: 前端页面错乱会导致后端功能报错, 谁又说的准呢
- 放行的意义是被匹配拦截的一些方法, 其中应该被排除的, 如果都没有被添加在拦截路径中, 则无需排除放行
- 如果登录成功之后, 会有session信息, 处于登录状态, 就不会被拦截了好像...
- 碰到的问题就是访问一个方法, 控制台多次经过拦截器, 就说明不该拦截的被拦截了, 拦截匹配的范围应该适当, 不要全包括了
-
重定向能跳到方法路径映射, 也能直接到视图
.sendRedirect()方法不会经过视图解析器,重定向也不会经过视图解析器 默认请求转发, 可以指定, 指定后就不管是请求转发还是重定向都不会经过视图解析器
所有被拦截之后应该重定向到一个方法再返回到错误或登录页面重新登录 -
配置MVC拦截器后能拦截方法路径映射, 也能拦截视图, 就比如上面提到的静态资源放行等
只是它的配置类的方法 registry.addPathPatterns()不能添加视图,而是方法请求映射;是可以的, 只是一般不会直接访问视图路径,而是通过方法URL访问@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") .excludePathPatterns("/userInfo/login", "/userInfo/loginPlease"); }
这个拦截器实现用户登录, 除了登录的请求映射和登录失败的重定向路径,其他都需要经过拦截器进行拦截, 如果登录过一次会保存session信息, 再访问其他路径不会进行拦截
登录拦截器类
@Component // xml配置的方式暂时不知道,
// 使用配置类解决, 需要将自定义重写方法的拦截器注入Spring容器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截生效...");
User user = (User) request.getSession().getAttribute("user");
System.out.println(request.getContextPath());
// 先验证其他方法是否被拦截, 再验证login是否被拦截,
// 如果login登录过后session会保留用户信息,下次直接访问add或delete方法路径就不用登录了
if (user == null) {// 判断session是否为空, 就是没有登录-->进行拦截重定向到登录页
response.sendRedirect(request.getContextPath() + "/userInfo/loginPlease"); // 重定向是可以到视图页面的login.html,但是这里要被放行,不然会出现重定向到一个不被放行的页面,又继续被拦截,出现反复进入拦截器拦截的错误(自己就犯了这个错误),所有想要被重定向到一个返回错误页面或者返回登录页的映射方法(貌似是拦截器配置类里不能exclude视图页面,所有要先走方法映射)
return false;
}
System.out.println("请求未被拦截");
System.out.println(user);
return true;
}
}
配置类
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/userInfo/login", "/userInfo/loginPlease");
}
}
登录控制器类
@Controller
@RequestMapping("/userInfo")
public class UserInfoController {
@ResponseBody
@RequestMapping("/login")
public ModelAndView userLogin(HttpSession session) {
System.out.println("用户登录...");
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
//
User user = new User();
user.setAge(188);
user.setName("tianjw");
session.setAttribute("user", user);
return mv;
}
@RequestMapping("/add")
public ModelAndView userAdd() {
System.out.println("用户登录...");
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
return mv;
}
@RequestMapping("/update")
public ModelAndView userUpdate() {
System.out.println("用户更新...");
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
return mv;
}
@RequestMapping("/delete")
public ModelAndView userDelete() {
System.out.println("用户删除...");
ModelAndView mv = new ModelAndView();
mv.setViewName("success");
return mv;
}
@RequestMapping("/loginPlease")
public ModelAndView loginPlease() {
System.out.println("请登录...");
ModelAndView mv = new ModelAndView();
mv.setViewName("login");
return mv;
}
}
标签:03,Spring,视图,mv,ModelAndView,注解,拦截,杂项
From: https://www.cnblogs.com/code-jia/p/18070618