Home 实习

0 75

https://blog.csdn.net/qh870754310/article/details/83780812

开始在使用Maven时,总是会听到nexus这个词,一会儿maven,一会儿nexus,当时很是困惑,nexus是什么呢,为什么它总是和maven一起被提到呢?

我们一步一步来了解吧。

 一、了解Maven,Maven用来干什么呢

1. 优秀的构建工具

通过简单的命令,能够完成清理、编译、测试、打包、部署等一系列过程。同时,不得不提的是,Maven是跨平台的无论是在Windows、还是在Linux或Mac上,都可以使用同样的命令。

2. 依赖管理工具

项目依赖的第三方的开源类库,都可以通过依赖的方式引入到项目中来。代替了原来需要首先下载第三方jar,再加入到项目中的方式。从而更好的解决了合作开发中依赖增多、版本不一致、版本冲突、依赖臃肿等问题。

具体是怎么实现的呢?Maven通过坐标系统准确的定位每一个构件,即通过坐标找到对应的Java类库。

3. 项目信息管理工具

能够管理项目描述、开发者列表、版本控制系统地址、许可证等一些比较零散的项目信息。除了直接的项目信息,通过Maven自动生成的站点,以及一些已有的插件,还能够轻松获得项目文档、测试报告、静态分析报告、源码版本、日志报告等非常具有价值的项目信息。

二、 Maven与Nexus

这个问题从Maven的第二个用处说起,依赖管理,通过在Pom中指定坐标的形式将jar引入到项目中。那这个过程,要经历怎样一个流程呢?从哪里寻找jar?下载的jar放到哪里?

将这个问题顺下来,就知道nexus和maven的关系了。

从哪里找到jar?项目用到的jar又存放在哪里?这引出了仓库的概念,maven通过仓库来统一管理各种构件。Maven的仓库分为本地仓库远程仓库。

当Maven根据坐标寻找构件时,它首先会查看本地仓库如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用

到了这里,问题的答案也就出来了。

首先,Nexus是一种远程仓库,根据上段的介绍,我们已经知道远程仓库的作用。在远程仓库中,默认的是中央仓库,中央仓库是Maven核心自带的远程仓库。那就使用中央仓库不就得了吗,为什么我们要安装Nexus呢?

我们从项目实际开发来看:

1.一些无法从外部仓库下载的构件,例如内部的项目还能部署到私服上,以便供其他依赖项目使用

2. 为了节省带宽和时间,在局域网内架设一个私有的仓库服务器,用其代理所有外部的远程仓库当本地Maven项目需要下载构件时先去私服请求,如果私服没有,则再去远程仓库请求,从远程仓库下载构件后,把构件缓存在私服。这样,即使暂时没有Internet链接,由于私服已经缓存了大量构件,整个项目还是可以正常使用的。同时,也降低了中央仓库的负荷。

Nexus仅仅是私服的一种。

0 39

基础功能模块发开完成了,接下来则是将我所写的功能模块组装到公司的OA系统上

首先,将子模块gqt导入OA模块所在文件夹导入子模块之后,在父模块的pom文件中将gqt功能模块添加到项目中

注意:此时要将gqt功能模块打成jar包如果没有添加到本机项目的依赖仓库里,则手动复制过去

项目开发,难免遇到与其他模块的交互,那么当我们要引入其他模块的类或者功能时,同样的在子功能项目的包中引入依赖同样的,其他子模块如果需要引入我们所写的功能模块,也需要同样的引入jar包

此时即可正常运行!!!

0 87

历经千辛万苦,主模块终于跑起来了,进入swagger文档,仔细阅读了相关的接口,然后测试,截图发给领导,走人

开启第二篇,功能开发

 

领导这次给我的任务是通过开发文档来建立数据库表

由于项目涉及的数据量不大,所以不需要考虑索引,又因为是设计单表,所以总的来说并不难

但我同样受益匪浅

 

首先 明确了unid的作用,某些项目开发时会维护一个或多个系统表,这些系统表类似于身份证系统,而unid就是身份证号码每产生一个新的数据库所定义的对象实体,就给他发一个独特的身份证号码—unid

 

比如在OA系统中,团组织是一个对象,团组织的书记也是一个对象

当我们创建了一个具体的团组织的时候,给它创建分配一个独特的unid,而设置一个书记(在数据库表中表现为新增一条数据)的时候,也给书记这个人,分配一个独特的unid,如下图

这样,我们在进行操作的时候,统一通过unid来进行,方便开发

同时,为了更好的实施开发,我制作了简约的思维导图

接下来就是代码的编写了,此处我学到的知识点许多(主要是swagger注解及其他),特此记录

 

@Data
@AllArgsConstructor     //有参构造
@NoArgsConstructor      //无参构造
@Accessors(chain = true)    //开启链式编程
@ApiModel("团组织信息")      //Swagger 模型
@JsonSerialize(using = ToStringSerializer.class)    //Long 数据类型 防止前后端传递时被截取

@TableId(value = “unid”) //mybatis-plus 主键(不加可能出现查询结果字段为null的现象)
@ApiModel:在实体类上边使用,标记类时swagger的解析类。 提供有关swagger模型的其它信息,类将在操作中用作类型时自动内省。
@ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改  如果Mapper.xml文件找不到有可能是编译之后 Mapper接口Mapper.xml不在同一个包中,可以通过target查看 接下来是Mybatis 动态SQL知识点,以及 SQL注入相关知识(需要继续补充) <resultMap>这里面property对应的是结果集的字段或属性,column对应的是数据库的列名或别名。 当然,它的功能远不止此https://www.jb51.net/article/162387.htm

<sql>+<include>实现SQL语句复用

未完待续…

0 77

2021.6.28入职

2021.6.29学习视频

2021.6.30正式开始开发(emmm,哭,把我实习生当正式工用了)

 

可以说这是本人第一次搭建企业级项目,一路上磕磕绊绊,总算在今天下午把自己写的功能模块成功合并到主模块上,并且通过了swagger的测试,必须记录下来,警醒自己还有很多的不足!

首先放上成功截图!

项目结构图

 

 

开发过程

当我作为一个实习生,正准备接下来的一个月摸鱼划水看文档的时候,亲爱的雨哥找到我,说

雨:“Springboot熟悉吗?”

我(这不得装一手?):“熟悉,写过三个项目,包括mybatis,redis,mq这些也还行,都用过”

雨:“很好,那你上手开发吧,明天把环境配一下”

我:???实习生入职第三天就开发,路子这么野的吗?环境?此时天真的我以为是配置Springboot开发环境,(毕竟咱之前不都是配个Springboot,自己电脑上数据库,redis什么的啥都有就上手开发了)

 

第二天

我踌躇满志,小小的配置环境能难得倒我吗?开玩笑,来吧

或许程序员大佬话都少吧,雨哥让我搭环境,前前后后,总共就这么几句话(我发誓我一句都没少,总共就这么几句)

Ok,文件接收完了,Git地址账号给了,雨哥不说话了,我要开始开发了

 

emmmmm,这对于我一个大三刚实习的学生来说是不是太残酷了点,真的不手把手带着我吗?

没办法,硬着头皮上吧

首先我使用了SourceTree去拉取GitLab上的项目代码,这个跟Git上拉取没什么不同,都是拉下来直接用解压,用idea打开就可以了,结构如下

Ok,启动IDEA,运行,成功,到此结束

当然不是,md,头一次见到微服务架构,震撼一百年,完全搞不懂入口在哪,真的是哪里亮了点哪里,就这样点

笑死,根本行不通,一片爆红

右侧Maven,找不到依赖

pom.xml文件就不用说了,也是一片红

启动类也没好到哪去

 

 

Maven爆红是因为Maven仓库里没有对应的依赖,或者没有导入,我可以理解,但是为什么启动类也爆红呢?

这就涉及到@ComponentScan 注解 的作用:

简版:@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中,注解定义如下。到这咱们就明白了,没有引入子模块,扫描子模块的包又怎么可行呢?

 

我所开发的这个项目相当于已经集成了,可以把这些用不上的先注释,只添加自己需要的模块就可以跑起来测试接口,因此,我第一次求助雨哥

得到了: 不需要用的模块就先注释(实际开发,如果是微服务架构,肯定用得上!因为是分组开发,所有有些模块咱们没有权限,也引入不了)

于是我把pom.xml里用不到的注释掉,又把启动类上扫描对应的包也注释,这样总算是不爆红了

 

 

就在此处,我学到了第一个重大的知识点

Maven仓库配置

可能是我才疏学浅,一直以来对Maven仓库都是不怎么管的,毕竟在学校导入的包和各种配置完全比不上企业级开发,导致我在学校的时候,从来!从来没配置过Maven仓库,吃了大亏!!!

项目开发要引入包,如果是网上的包,比如什么mybatis,spring的包,我们都知道,直接去Maven官网找,复制到自己项目的pom文件即可,如下图

这样,IDEA就会乖乖帮我们把需要的依赖添加到本机的maven仓库,一般来说没什么问题

但是,如果遇到要添加自用的包,例如公司的依赖,同事的依赖, 这个时候在网上搜索不到,怎么办?或者说需要咱们自己查看项目依赖所在的repository,就需要了解相关的maven仓库配置问题!!!

配置Maven仓库并不复杂,但必须要细致,配置Maven详情 https://www.cnblogs.com/phpdragon/p/7216626.html

简单流程:(只显示了在IDEA层面操作的,实际上还要添加环境变量,配置setting.xml文件)

通过Local repository我们可以找到项目的依赖来源,即仓库具体地址,settings.xml设置的是自动下载jar包的存放地址

如果我们需要手动的修改Maven仓库里的东西,就在这里修改

言归正传,当我终于导好了项目所需要依赖时,再次点击运行,终于成功了!

未完待续…

0 129

sql是正确的,但是商品这个对象只有price(价格),stock(存量)是有值的,其他的都没有.

我自己的解决办法是:不使用resultType(问题很多),而是使用resultMap.

下面是我的应用场景和解决思路.

/**
* 商品
*/
public class Goods {
/**
* 商品id
*/
private Integer goodsId;
/**
* 商品名称
*/
private String goodsName;
/**
* 商品所属商店的id
*/
private Integer shId;
/**
* 商品销量
*/
private Integer sales;
/**
* 商品参考价格
*/
private Double priceRefer;
/**
* 价格
*/
private Double price;
/**
* 库存量
*/
private Integer stock;

/**
* 商品的状态吗
*/
private GoodsEnum goodsEnum;
//getter,setter
}
“goodsId”: null,
“goodsName”: null,
“shId”: null,
“sales”: 1,
“priceRefer”: null,
“price”: 9.9,
“stock”: 1,
“goodsEnum”: null
首先,查出来结果了,并且sql语句没有报错,排除数据库层没有查出来结果。

查看相关的逻辑代码后进行debug,定位错误位置在Mybatis的返回值问题上.

然后在百度的启发下,发现,对象中有值的属性都在数据库中对应的列名中没有”_”,所有为null的列名中都包含下划线.

然后发现自己使用的是ResultType=”cn.edu.bean.Goods”,于是改成我写好的一个映射resultMap(resultMap=”BaseResultMap”)即可。

<resultMap id=”BaseResultMap” type=”cn.edu.zzuli.bean.Goods”>
<id column=”goods_id” property=”goodsId” jdbcType=”INTEGER”/>
<result column=”goods_name” property=”goodsName” jdbcType=”VARCHAR”/>
<result column=”sh_id” property=”shId” jdbcType=”INTEGER”/>
<result column=”sales” property=”sales” jdbcType=”INTEGER”/>
<result column=”price_refer” property=”priceRefer” jdbcType=”DOUBLE”/>
<result column=”price” property=”price” jdbcType=”DOUBLE”/>
<result column=”stock” property=”stock” jdbcType=”INTEGER”/>
</resultMap>
我猜想:应该是resultType对小写驼峰命名法和数据库的下划线命名法适应的不太好,才会出现这个问题。
当然有人如果知道答案,希望可以在评论留言,一起学习一起进步。

.当然也有可能是以下这种情况:sql语句中使用了别名机制,导致mybatis没有办法区分那个是对的(猜测)。

转载过来供大家参考。

<resultMap id=”BaseResultMap” type=”com.trhui.ebook.dao.model.MerchantUser”>
<id column=”MU_ID” jdbcType=”BIGINT” property=”muId”/>
<result column=”USER_ID” jdbcType=”BIGINT” property=”userId”/>
<result column=”MERCHANT_NO” jdbcType=”VARCHAR” property=”merchantNo”/>
<result column=”USER_PHONE” jdbcType=”VARCHAR” property=”userPhone”/>
<result column=”GRANTED” jdbcType=”VARCHAR” property=”granted”/>
<result column=”CREATE_DATE” jdbcType=”TIMESTAMP” property=”createDate”/>
<result column=”MERCHANT_USER_ID” jdbcType=”VARCHAR” property=”merchantUserId”/>
<result column=”STATUS” jdbcType=”VARCHAR” property=”status”/>
<result column=”ENTE_USER_NO” jdbcType=”VARCHAR” property=”enteUserNo”></result>
</resultMap>

<sql id=”Base_Column_List”>
MU_ID muId,
USER_ID userId,
MERCHANT_NO merchantNo,
USER_PHONE userPhone,
GRANTED granted,
CREATE_DATE createDate,
MERCHANT_USER_ID merchantUserId,
ENTE_USER_NO enteUserNo,
STATUS status
</sql>
<select id=”selectByPrimaryKey” parameterType=”java.lang.Long” resultMap=”BaseResultMap”>
select
<include refid=”Base_Column_List”/>
from merchant_user
where MU_ID = #{muId,jdbcType=BIGINT}
</select>
如果返回的对象是resultMap 那么就不要给字段加别名了,问题就是出在这里,将字段别名去了就OK;

如果要给字段加别名,那么你就直接返回该对象就好了,路径要写全,如:resultType=”com.trhui.ebook.dao.model.MerchantUser”

而不是返回resultMap=”BaseResultMap”

 

补充:也可能是使用了Mabatis – Plus 而没有表示主键!https://blog.csdn.net/YiWangJiuShiXingFu/article/details/108378299

 

一、原因
mybatis_plus 默认会使用 “id” 为主键字段,如果数据库的主键字段不是“id”的话,使用mybatis-plus中的 selectById ,getById 方法查询数据是查询不出来的

二、解决
在实体类的主键字段加上@TableId(value =“数据库你的主键字段”)注解即可
例如我的是product_id为主键。

利用SQL注入漏洞登录后台

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击

sql注入

什么时候最易受到sql注入攻击

当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的 字符串来传递,也会发生sql注入。sql注入可能导致攻击者使用应用程序登陆在数据库中执行命令。如果应用程序使用特权过高的帐户连接到数据库,这种问 题会变得很严重。在某些表单中,用户输入的内容直接用来构造动态sql命令,或者作为存储过程的输入参数,这些表单特别容易受到sql注入的攻击。而许多 网站程序在编写时,没有对用户输入的合法性进行判断或者程序中本身的变量处理不当,使应用程序存在安全隐患。这样,用户就可以提交一段数据库查询的代码, 根据程序返回的结果,获得一些敏感的信息或者控制整个服务器,于是sql注入就发生了。

如何防止SQL注入

归纳一下,主要有以下几点:

1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和

双”-“进行转换等。

2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。

3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。

5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装

6.sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。

例子一、SQL注入实例详解(以上测试均假设服务器未开启magic_quote_gpc)https://blog.csdn.net/forest_fire/article/details/50944708

1) 前期准备工作

先来演示通过SQL注入漏洞,登入后台管理员界面

首先,创建一张试验用的数据表:

CREATE TABLE `users` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`username` varchar(64) NOT NULL,

`password` varchar(64) NOT NULL,

`email` varchar(64) NOT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `username` (`username`)

) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

添加一条记录用于测试:

INSERT INTO users (username,password,email)

VALUES(‘MarcoFly’,md5(‘test’),’marcofly@test.com’);

接下来,贴上登录界面的源代码:

<html>
<head>
<title>Sql注入演示</title>
<meta http-equiv=”content-type” content=”text/html;charset=utf-8″>
</head>

<body >
<form action=”validate.php” method=”post”>
<fieldset >
<legend>Sql注入演示</legend>
<table>
<tr>
<td>用户名:</td>
<td><input type=”text” name=”username”></td>
</tr>
<tr>
<td>密&nbsp;&nbsp;码:</td>
<td><input type=”text” name=”password”></td>
</tr>
<tr>
<td><input type=”submit” value=”提交”></td>
<td><input type=”reset” value=”重置”></td>
</tr>
</table>
</fieldset>
</form>
</body>
</html>

附上效果图:

\
  当用户点击提交按钮的时候,将会把表单数据提交给validate.php页面,validate.php页面用来判断用户输入的用户名和密码有没有都符合要求(这一步至关重要,也往往是SQL漏洞所在)

代码如下:

<html>
<head>
<title>登录验证</title>
<meta http-equiv=”content-type” content=”text/html;charset=utf-8″>
</head>

<body>
<?php

$conn=@mysql_connect(“localhost”,’root’,”) or die(“数据库连接失败!”);;

mysql_select_db(“injection”,$conn) or die(“您要选择的数据库不存在”);

$name=$_POST[‘username’];

$pwd=$_POST[‘password’];

$sql=”select * from users where username=’$name’ and password=’$pwd'”;

$query=mysql_query($sql);

$arr=mysql_fetch_array($query);

if(is_array($arr)){

header(“Location:manager.php”);

}else{

echo “您的用户名或密码输入有误,<a href=\”Login.php\”>请重新登录!</a>”;

}

?>
</body>
</html>

注意到了没有,我们直接将用户提交过来的数据(用户名和密码)直接拿去执行,并没有实现进行特殊字符过滤,待会你们将明白,这是致命的。

代码分析:如果,用户名和密码都匹配成功的话,将跳转到管理员操作界面(manager.php),不成功,则给出友好提示信息。

登录成功的界面:

\
  登录失败的提示:

\
  到这里,前期工作已经做好了,接下来将展开我们的重头戏:SQL注入

2) 构造SQL语句

填好正确的用户名(marcofly)和密码(test)后,点击提交,将会返回给我们“欢迎管理员”的界面。

select * from users where username=’marcofly’ and password=md5(‘test’)

很明显,用户名和密码都和我们之前给出的一样,肯定能够成功登陆。但是,如果我们输入一个错误的用户名或密码呢?很明显,肯定登入不了吧。恩,正常情况下是如此,但是对于有SQL注入漏洞的网站来说,只要构造个特殊的“字符串”,照样能够成功登录。

比如:在用户名输入框中输入:’ or 1=1#,密码随便输入,这时候的合成后的SQL查询语句为:

select * from users where username=” or 1=1#’ and password=md5(”)

语义分析:“#”在mysql中是注释符,这样井号后面的内容将被mysql视为注释内容,这样就不会去执行了,换句话说,以下的两句sql语句等价:

select * from users where username=” or 1=1#’ and password=md5(”)

等价于

select * from users where username=” or 1=1

SQL注入采用的’ OR 1=1 # 是什么意思呢?

最后一个#号有什么意义呢?
SELECT * FROM test WHERE name=” OR 1=1 #’ AND age=’20’
这后面写的 #’ 是什么意思呢? 求指教
# 可以注释掉后面的一行SQL代码

相当于去掉了一个where条件

MySQL 注释, 过滤掉后面的SQL语句,使其不起作用

因为1=1永远是都是成立的,即where子句总是为真,将该sql进一步简化之后,等价于如下select语句:

select * from users 没错,该sql语句的作用是检索users表中的所有字段

小技巧:一个经构造后的sql语句竟有如此可怕的破坏力,相信你看到这后,开始对sql注入有了一个理性的认识了吧~

有漏洞的脚本才有机会给你攻击,比如一个带参数的删除脚本a.asp?action=del&id=2你可以改为a.asp?action=del&id=2 or 1这样就有可能删除全部数据——sql注入就是通过类似的手段来破坏数据

尝试:在我的毕业设计首页搜索中输入【123′ or 1=(select count(1) from tb_users)–】会查询不出人和数据  并且不会报错   通过这样可以判断是否存在表tb_users

原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html

for update 的作用和目的

select for update 是为了在查询时,对这条数据进行加锁,避免其他用户以该表进行插入,修改或删除等操作,造成表的不一致性.

简而言之:查询加锁;

 几个类似的场景

select * from t for update 会等待行锁释放之后,返回查询结果。
select * from t for update nowait 不等待行锁释放,提示锁冲突,不返回结果
select * from t for update wait 5 等待5秒,若行锁仍未释放,则提示锁冲突,不返回结果
select * from t for update skip locked 查询返回查询结果,但忽略有行锁的记录

SELECT…FOR UPDATE 语句的语法

SELECT … FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
其中:
OF 子句用于指定即将更新的列,即锁定行上的特定列。
WAIT 子句指定等待其他用户释放锁的秒数,防止无限期的等待。

“使用FOR UPDATE WAIT”子句的优点

1防止无限期地等待被锁定的行;
2允许应用程序中对锁的等待时间进行更多的控制。
3对于交互式应用程序非常有用,因为这些用户不能等待不确定
4 若使用了skip locked,则可以越过锁定的行,不会报告由wait n 引发的‘资源忙’异常报告

补充几点

分成两类:加锁范围子句加锁行为子句

加锁范围子句:在select…for update之后,可以使用of子句选择对select的特定数据表进行加锁操作。默认情况下,不使用of子句表示在select所有的数据表中加锁

加锁行为子句:当我们进行for update的操作时,与普通select存在很大不同。一般select是不需要考虑数据是否被锁定,最多根据多版本一致读的特性读取之前的版本。加入for update之后,Oracle就要求启动一个新事务,尝试对数据进行加锁。如果当前已经被加锁,默认的行为必然是block等待。使用nowait子句的作用就是避免进行等待,当发现请求加锁资源被锁定未释放的时候,直接报错返回。

在日常中,我们对for update的使用还是比较普遍的,特别是在如pl/sql developer中手工修改数据。此时只是觉得方便,而对for update真正的含义缺乏理解。

For update是Oracle提供的手工提高锁级别和范围的特例语句。Oracle的锁机制是目前各类型数据库锁机制中比较优秀的。所以,Oracle认为一般不需要用户和应用直接进行锁的控制和提升。甚至认为死锁这类锁相关问题的出现场景,大都与手工提升锁有关。

所以,Oracle并不推荐使用for update作为日常开发使用。而且,在平时开发和运维中,使用了for update却忘记提交,会引起很多锁表故障。 那么,什么时候需要使用for update?就是那些需要业务层面数据独占时,可以考虑使用for update。场景上,比如火车票订票,在屏幕上显示邮票,而真正进行出票时,需要重新确定一下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使用for update。这是统一的解决方案方案问题,需要前期有所准备。

今天在公司学习项目代码的时候看到了

private static final long serialVersionUID = 1L;
特此记录


1、首先谈谈为什么要序列化对象

– 把对象转换为字节序列的过程称为对象的序列化。
– 把字节序列恢复为对象的过程称为对象的反序列化。

对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象

2、为什么要使用SerialversionUID呢

简单看一下 Serializable接口的说明

If a serializable class does not explicitly declare a serialVersionUID,
then the serialization runtime will calculate a default
serialVersionUID value for that class based on various aspects of the class,
as described in the Java(TM) Object Serialization Specification.

如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID
However, it is stronglyrecommended that all serializable classes explicitly declareserialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedInvalidClassExceptions during deserialization.
但是强烈建议用户自定义一个serialVersionUID,因为默认的serialVersinUID对于class的细节非常敏感反序列化时可能会导致InvalidClassException这个异常。

其实也可以这样理解,相当于快递的打包和拆包,里面的东西要保持一致,不能人为的去改变他,不然就交易不成功。
序列化与反序列化也是一样,而版本号的存在就是要是里面内容要是不一致,不然就报错。像一个防伪码一样。

@RequestParam注解

1、作用:

@RequestParam:将请求参数绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解)

2、语法:

语法:@RequestParam(value=”参数名”,required=”true/false”,defaultValue=””)

value:参数名

required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。

defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值

详解:https://blog.csdn.net/sswqzx/article/details/84195043

@RequestBody的使用(转载!!!好文!!!)

提示:建议一定要看后面的@RequestBody的核心逻辑源码以及六个重要结论!本文前半部分的内容都是一些基
本知识常识,可选择性跳过。

声明:本文是基于SpringBoot,进行的演示说明。

 

基础知识介绍:
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。

注:一个请求,只有一个RequestBody;一个请求,可以有多个RequestParam

注:当同时使用@RequestParam()和@RequestBody时,@RequestParam()指定的参数可以是普通元素、
数组、集合、对象等等(即:当,@RequestBody 与@RequestParam()可以同时使用时,原SpringMVC接收
参数的机制不变,只不过RequestBody 接收的是请求体里面的数据;而RequestParam接收的是key-value
里面的参数,所以它会被切面进行处理从而可以用普通元素、数组、集合、对象等接收)。
即:如果参数时放在请求体中,application/json传入后台的话,那么后台要用@RequestBody才能接收到;
如果不是放在请求体中的话,那么后台接收前台传过来的参数时,要用@RequestParam来接收,或
则形参前 什么也不写也能接收。

注:如果参数前写了@RequestParam(xxx),那么前端必须有对应的xxx名字才行(不管其是否有值,当然可以通
过设置该注解的required属性来调节是否必须传),如果没有xxx名的话,那么请求会出错,报400。

注:如果参数前不写@RequestParam(xxx)的话,那么就前端可以有可以没有对应的xxx名字才行,如果有xxx名
的话,那么就会自动匹配;没有的话,请求也能正确发送。
追注:这里与feign消费服务时不同;feign消费服务时,如果参数前什么也不写,那么会被默认是
@RequestBody的。

如果后端参数是一个对象,且该参数前是以@RequestBody修饰的,那么前端传递json参数时,必须满足以下要求:

后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为),这一条我会在下面详细分析,其他的都可简单略过,但是本文末的核心逻辑代码以及几个结论一定要看! 实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性

json字符串中,如果value为””的话,后端对应属性如果是String类型的,那么接受到的就是””,如果是后端属性的类型是Integer、Double等类型,那么接收到的就是null。

json字符串中,如果value为null的话,后端对应收到的就是null。

如果某个参数没有value的话,在传json字符串给后端时,要么干脆就不把该字段写到json字符串中;要么写value时, 必须有值,null 或””都行千万不能有类似”stature”:,这样的写法,如:

注:关于@RequestParam()的用法,这里就不再一一说明了,可详见 《程序员成长笔记(一)》中的相关章节。

 

示例详细说明:

先给出两个等下要用到的实体类

User实体类:

 

Team实体类:

@RequestBody直接以String接收前端传过来的json数据:

后端对应的Controller:

使用PostMan测试:

@RequestBody以简单对象接收前端传过来的json数据:

后端对应的Controller:

使用PostMan测试:

@RequestBody以复杂对象接收前端传过来的json数据:

后端对应的Controller:

使用PostMan测试:

 

@RequestBody与简单的@RequestParam()同时使用:

后端对应的Controller:

使用PostMan测试:

@RequestBody与复杂的@RequestParam()同时使用:

后端对应的Controller:

使用PostMan测试:

 

@RequestBody接收请求体中的json数据;不加注解接收URL中的数据并组装为对象:

后端对应的Controller:

使用PostMan测试:

注:如果在后端方法参数前,指定了@RequestParam()的话,那么前端必须要有对应字段才行(当然可以通过设置
该注解的required属性来调节是否必须传),否者会报错;如果参数前没有任何该注解,那么前端可以传,也可
以不传,如:

上图中,如果我们传参中没有指定token,那么请求能正常进去,但是token为null;如果在String token前指定了@RequestParam(“token”),那么前端必须要有token这个键时,请求才能正常进去,否者报400错误。

https://blog.csdn.net/justry_deng/article/details/80972817/

 

@PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值

https://blog.csdn.net/sswqzx/article/details/84194979