6.5 学习记录

224 阅读5分钟

安恒实习

公司项目学习

前端填写表单,后端写入的实现

@Requestbody的使用和底层源码学习

简介(官方)

指示方法参数的注释应绑定到Web请求的主体。请求的主体通过a HttpMessageConverter来解析方法参数,具体取决于请求的内容类型。(可选)可以通过使用注释参数来应用自动验证@Valid。

作用

@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。

a. content-type : multipart/form-data 
    这种格式使用@RequestBody处理不了。
b. content-type : application/x-www-form-urlencoded 
    form表单形式提交的数据格式,可以使用@RequestBody,也可以使用其他注解例如@RequestParam, @ModelAttribute进行接收。
c. content-type : 其他数据格式 
    必须使用@RequestBody进行接收。

使用

只需在方法参数中对目标对象或变量用@RequestBody进行注释即可使用,注意一个方法中只能使用一次requestBody,因为spring会将request请求中的body都合并到一个json中,也就是说即使有多个@RequestBody注解,只能有一个对象或变量接收。 那么如果我们有多个参数需要传怎么办呢?新建一个包含所有参数的类,body中的参数会与类中相同名称的变量一一对应。

源码实现

  • @RequestBody 注解则是将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象; Spring中处理@RequestBody主要依靠的是AbstractMessageConverterMethodArgumentResolver这个类,它实现了HandlerMethodArgumentResolver(在另一篇文章中已经讲过).处理网络请求的方法是readWithMessageConverters这个方法(只截取了部分)。

该方法首先通过获得inputMessage中的header,然后从header中取出contenttype。 而真正将json转换为对象的则在下面的read()方法中。首先进行简单的判断,converter是否是GenericHttpMessageConverter的一个实例,用canRead方法进行判断是否可以转换(后面也是一系列的判断)。一直到下面的read方法方法,将inputMessage转换成目标类,然后使用afterBodyRead方法进行格式化,转换成目标对象。最后会执行我们注解了@RequestBody的对象类里的set方法,将从json转换来的对应变量赋值给目标对象。

HttpMessageConverter接口定义方法,图片来自csdn作者喵喵小姐 blog.csdn.net/qq_34500957…

拓展

Spark学习 Yarn学习

每日一题

题目 51.N皇后

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例:

输入: 4 输出: [ [".Q..", // 解法 1 "...Q", "Q...", "..Q."],

["..Q.", // 解法 2 "Q...", "...Q", ".Q.."] ] 解释: 4 皇后问题存在两个不同的解法。

思路

这道题的输出非常难受...我的思路是用一个List<int[][]>存储结果集,"0"代表空位,输出",","1"代表皇后,输出Q,然后用按行遍历List<int[][]>里的int[][],用stringbuffer拼接结果,存入List,将List存入结果集List<List>。 再来关注这道题本身,皇后问题可以说是一个经典的回溯算法问题,要解决这个问题主要分为两个步骤

  1. 如何判断当前放入的皇后是否符合要求。
  2. 当不满足条件时及时进行回溯。 关于1,我的思路是用一个n X n的二维数组记录当前已存在的皇后的攻击区域,由于是n * n的棋盘,从左下向右上的斜线,行号和列号之和一定是一个常数;自左上向右下的斜线,行号和列好之差也为常数,因此我们可以利用这个特点,标记会被攻击到的区域。

代码

class Solution { int rows[]; // "hill" diagonals int hills[]; // "dale" diagonals int dales[]; int n; // output List<List> output = new ArrayList(); // queens positions int queens[];

public boolean isNotUnderAttack(int row, int col) { int res = rows[col] + hills[row - col + 2 * n] + dales[row + col]; return (res == 0) ? true : false; }

public void placeQueen(int row, int col) { queens[row] = col; rows[col] = 1; hills[row - col + 2 * n] = 1; // "hill" diagonals dales[row + col] = 1; //"dale" diagonals }

public void removeQueen(int row, int col) { queens[row] = 0; rows[col] = 0; hills[row - col + 2 * n] = 0; dales[row + col] = 0; }

public void addSolution() { List solution = new ArrayList(); for (int i = 0; i < n; ++i) { int col = queens[i]; StringBuilder sb = new StringBuilder(); for(int j = 0; j < col; ++j) sb.append("."); sb.append("Q"); for(int j = 0; j < n - col - 1; ++j) sb.append("."); solution.add(sb.toString()); } output.add(solution); }

public void backtrack(int row) { for (int col = 0; col < n; col++) { if (isNotUnderAttack(row, col)) { placeQueen(row, col); // if n queens are already placed if (row + 1 == n) addSolution(); // if not proceed to place the rest else backtrack(row + 1); // backtrack removeQueen(row, col); } } }

public List<List> solveNQueens(int n) { this.n = n; rows = new int[n]; hills = new int[4 * n - 1]; dales = new int[2 * n - 1]; queens = new int[n];

backtrack(0);
return output;

} }

复杂度分析

  • 时间复杂度:\mathcal{O}(N!)O(N!). 放置第 1 个皇后有 N 种可能的方法,放置两个皇后的方法不超过 N (N - 2) ,放置 3 个皇后的方法不超过 N(N - 2)(N - 4) ,以此类推。总体上,时间复杂度为 \mathcal{O}(N!)O(N!) .
  • 空间复杂度:\mathcal{O}(N)O(N) . 需要保存对角线和行的信息。