0%

知识点

  • about date jdbcType

    1
    2
    #{beginDate,jdbcType=DATE} (no time of the day), or
    #{beginDate,jdbcType=TIMESTAMP} (if you need to include the time of the day).

And the Java parameter you want to apply should be of type:

1
2
3
java.sql.Date (date without time)
java.sql.Timestamp (timestamp)
java.util.Date (date and time).

  • the Greater Than/Equal Operator and the Less Than/Equal Operators:
    1
    2
    ROWNUM >= 20
    ROWNUM <= 20

问题解决

使用SpringMVC+Mybatis框架写项目的时候,在mapper里面的sql语句

1
2
3
<if test="updateTime != null">
and update_time &gt; #{updateTime,jdbcType=TIMESTAMP}
</if>

出错:There is no getter for property named 'updateTime' in 'class java.util.Date'

原因是:
如果将and语句中的#{属性}写在if语句中,mybatis会去对象中从它的get方法中取值,而我之前是直接传递的值,并没有封装对象。
解决办法:

 1. 把updateTime需改为date
2. 把updateTime代表的参数封装到一个对象中

配置文件

  • ```
    bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等

    application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。

    加载顺序:bootstrap.yml > application.yml > application-dev(prod).yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20



    ## 问题随记

    ### Spring Boot通过Mybatis,使用mapper接口和xml配置sql,连接数据库

    - 首先在配置文件application.properties

    ```properties
    spring.datasource.url=jdbc:mysql://localhost:3306/test
    spring.datasource.username=***
    spring.datasource.password=***
    spring.datasource.driverClassName=com.mysql.jdbc.Driver

    #mybatis.typeAliasesPackage:为实体对象所在的包,跟数据库表一一对应
    #mybatis.mapperLocations:mapper文件的位置

    mybatis.typeAliasesPackage=com.xxx.model
    mybatis.mapperLocations=classpath:mybatis/mapper/*Mapper.xml
  • 在启动类Application.java中写上配置信息

    1
    2
    3
    4
    5
    6
    7
    8
    @SpringBootApplication
    @MapperScan("com.xxx.dao") // mybatis扫描路径,针对的是接口Mapper类
    public class DailyreportApplication{

    public static void main(String[] args) {
    SpringApplication.run(DailyreportApplication.class, args);
    }
    }
  1. mysql连接异常java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Date
  • 解决办法jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull

文件

  • 提交单个文件

    1
    2
    3
    git commit <file> -m "your comment" 
    git pull
    git push
  • 提交多个文件,但是需要排除指定的文件

    1
    2
    3
    git add -u
    git reset -- main/dontcheckmein.txt
    然后进行commit、pull等操作

Git fork后的分支,更新最新的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sourcer为源项目代码
forker为fork之后的项目代码

1、找一个空的目录下签出 fork 后的代码
git clone https://github.com/sourcer/demo.git
查看 remote 信息
git remote -v

2、然后添加源项目地址(距离定义为 source)
git remote add source https://github.com/forker/demo.git
查看 remote 信息,可以看到新增两条信息
git remote -v

3、fetch 源项目
git fetch source

4、合并代码
git merge source/master

5、把合并最新的代码推送到你的fork项目上
git push origin master

比较文件,在不同版本的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# uncommited file to HEAD
git diff <path>

# uncommited file to before last commit
git diff HEAD^ -- <path>

#last commit to before last commit
git diff HEAD^ HEAD -- <path>

#difference between HEAD and n-th grandparent
git diff HEAD~n HEAD -- <path>

#Another cool feature is whatchanged command
git whatchanged -- <path>

查看每一行是哪次提交最后修改的

1
git blame filename 

列出文件的所有修改记录

1
git log -p filename

删除远程仓库文件,但保留本地文件系统的文件

1
2
3
4
# 文件
git rm --cached path/to/file
# 目录
git rm -r --cached path/to/directory

回滚代码

  • method 1: 重置当前分支的 HEAD 指针以及工作目录和暂存区的内容到指定的提交,擦除了目标提交之后的所有提交历史。

    1
    git reset --hard <commit-id>
  • Method 2: 只想回滚到指定提交,并保留后续提交历史

    1
    git revert <commit-id>

分支

查看分支对应的远程分支

git branch -vv

更改当前分支对应的远程分支

git branch -u origin/develop

回滚远程分支

1、本地代码回滚到上一版本

git reset –hard HEAD~1

(或者回滚到指定版本commitId)

git reset –hard commitId

2、加入-f参数,强制提交,远程端将强制跟新到reset版本

git push -f

拉取远程分支

First, fetch the remote branches:

git fetch origin

Next, checkout the branch you want. In this case, the branch we want is called “branchxyz”.

git checkout -b branchxyz origin/branchxyz

新建分支

  • To create a new branch from a branch you do NOT have checked out:

    git branch new_branch from_branch

  • To create a new branch from the branch you DO have checked out:

    git branch new_branch

  • To create and check out a new branch from the branch you DO have checked out:

    git checkout -b new_branch

  • To create and check out a new branch from a branch you do NOT have checked out:

    git checkout -b new_branch from_branch

  • To rename a branch

    git branch -m old_name new_name

推送新分支到远程

在新建分支完成的前提下

  1. 将develop分支推送到远程

    git push origin new_branch:new_branch

  2. 建立本地至上游(远程)分支的链接

    git branch --set-upstream-to=origin/new_branch new_branch

    如果要推送到的远程分支 origin/new_branch 与本地分支 new_branch 名字相同,那可以使用

    git branch –set-upstream-to origin new_branch

删除分支

1
2
3
4
5
6
7
8
// delete branch locally (如果要删除这个分支的话,需要跳转至其他分支后进行删除操作)
git branch -d localBranchName

// delete branch remotely
git push origin --delete remoteBranchName

//If someone else has already deleted the branch, you just do below
git fetch -p

重命名分支

1
git branch -m new-branch-name

stash

在Git中,stash命令用于暂存当前未提交的代码修改,以便在后续时刻再次应用它们。它可以暂存已修改但还未添加到暂存区的文件,也可以暂存已经添加到暂存区但还未提交的文件。

以下是stash命令的使用方式:

  1. 暂存当前修改:(这个命令将当前的修改暂存起来,让你的工作目录变成干净的状态。)

    1
    git stash
  2. 恢复暂存的修改:

    1
    git stash apply

    这个命令将之前暂存的修改应用到当前分支上。如果你有多个stash,可以使用git stash apply stash@{n}来指定恢复某个特定的stash。

  3. 删除stash:

    1
    git stash drop

    这个命令会删除最近的一个stash。

  4. 列出所有stash:

    1
    git stash list
  5. 应用并删除stash:

    1
    git stash pop

    这个命令相当于git stash applygit stash drop的组合,它会将最近的一个stash应用到当前分支,并将其删除。

  6. 暂存特定的文件:

    1
    git stash push path/to/file

    这个命令可以将指定的文件暂存起来,而不是暂存整个工作目录。

  7. 给stash添加描述:

    1
    git stash save "stash message"

rebase

git rebase 用法详解与工作原理

How to Rebase a Fork

  1. 更新本地主分支(通常是 master 或 main): 获取原始仓库的最新更改并合并到你的本地主分支:

    1
    2
    git checkout master  # 切换到你的本地主分支
    git pull upstream master # 从原始仓库拉取最新更改到本地主分支

    1
    git fetch upstream
  2. 切换到你的分支并进行 rebase: 切换到你的分支并将其 rebase 到主分支上:

    • 如果是新分支
    1
    2
    git checkout <新分支>
    git rebase master # 将新分支 rebase 到你的本地主分支
    • 如果是已有分支
    1
    2
    git checkout <已有分支>
    git rebase upstream/master
  3. 解决冲突(如果有): 如果在 rebase 过程中出现冲突,你需要手动解决冲突,然后使用 git add 标记为已解决。

    • 展示冲突代码(可省略)
    1
    git diff --name-only --diff-filter=U
    • 解决代码冲突
      • IDE手动解决
      • vimdiff解决
      • meld解决
    • 解决之后
    1
    2
    3
    git add .
    git commit -m "xxx"
    git rebase --continue
    • 终止rebase
    1
    git rebase --abort
  4. 推送更改到远程仓库: 推送你的更改到远程仓库:

    • 如果是新分支
    1
    2
    3
    git push origin <分支> --force  # 强制推送到你的 fork 仓库的新分支上

    git push -f origin <分支>

    请注意:使用 --force 参数进行强制推送时,请确保你了解它的影响。它可能会覆盖远程分支的历史记录,因此务必小心操作。

    • 如果是已有分支
    1
    git push
  5. 创建 Pull Request: 在你的 fork 仓库中,从新分支创建一个 Pull Request(PR),将你的更改合并到原始仓库的目标分支

commit rule

1
2
3
4
5
<type>(<scope>): <subject>

<body>

<footer>
  • Type

    You can use your own commit types, but here are the most common use cases:

    • feat: a new feature, or change to an existing feature.

    • fix: Fixing a bug or known issue in code.

    • test: Adding additional tests for existing features.

    • chore: Updating build tools, like webpack, gulp, ascripts, etc.

    • docs: Update to documentation like README, wiki, etc.

  • Scope

    The scope of the commit can be kept as granular as required and is bound to change based on the complexity of the project. If you are starting off a project, it might not seem necessary at the beginning, although, it is highly recommended as it makes you think twice and harder about the changes that you are about to push.

  • reference 7 Rules for Writing a Good Commit Message

squash/reword commit

  1. merge the last 3 commits into a single commit.

    1
    git rebase -i HEAD~3
  2. replace all those pick with squash (or simply s) apart from the first one.

    Note: pick or p will only use those commits, but squash or s will use them and combine them all together.

    The first commit is the one you will combine them into without losing your changes.

    注意,一般需要 squash的是后面的commit,需要保证第一条(最早的)commit 信息不被 squash

  3. After doing that, save the file and close it. Git will open up another editor where you can see the new commit message it generates for you.

    You can get rid of all of them and add your custom message:

    Or you can leave it as is. If you add a new commit message, save the file and close it.

  4. Pushing changes, You should run git push to add a new commit to the remote origin. If you have already pushed your commits, then you should force push them using the git push command with — force flag (suppose, the name of remote is origin, which is by default)

    1
    git push --force origin HEAD

中途如需终止rebase,运行 git rebase –abort

remote

fork remote

docs.github.com

初始化仓库

  1. List the current configured remote repository for your fork.

    1
    2
    3
    $ git remote -v
    > origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
    > origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
  2. Specify a new remote upstream repository that will be synced with the fork.

    1
    git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
  3. Verify the new upstream repository you’ve specified for your fork.

    1
    2
    3
    4
    5
    $ git remote -v
    > origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
    > origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
    > upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
    > upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push)

同步代码

  1. Change the current working directory to your local project.

  2. Fetch the branches and their respective commits from the upstream repository. Commits to BRANCHNAME will be stored in the local branch upstream/BRANCHNAME.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ git fetch upstream
    > remote: Counting objects: 75, done.
    > remote: Compressing objects: 100% (53/53), done.
    > remote: Total 62 (delta 27), reused 44 (delta 9)
    > Unpacking objects: 100% (62/62), done.
    > From https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
    > * [new branch] main -> upstream/main

    # 指定fetch某个分支
    git fetch <remote> <branch>
  3. Check out your fork’s local default branch - in this case, we use main.

    1
    2
    $ git checkout main
    > Switched to branch 'main'
  4. Merge the changes from the upstream default branch - in this case, upstream/main - into your local default branch. This brings your fork’s default branch into sync with the upstream repository, without losing your local changes.

    1
    2
    3
    4
    5
    6
    7
    8
    $ git merge upstream/main
    > Updating a422352..5fdff0f
    > Fast-forward
    > README | 9 -------
    > README.md | 7 ++++++
    > 2 files changed, 7 insertions(+), 9 deletions(-)
    > delete mode 100644 README
    > create mode 100644 README.md

    If your local branch didn’t have any unique commits, Git will perform a fast-forward. For more information, see Basic Branching and Merging in the Git documentation.

    1
    2
    3
    4
    5
    $ git merge upstream/main
    > Updating 34e91da..16c56ad
    > Fast-forward
    > README.md | 5 +++--
    > 1 file changed, 3 insertions(+), 2 deletions(-)

    If your local branch had unique commits, you may need to resolve conflicts. For more information, see “Addressing merge conflicts.”

submodule

对于项目中包含子项目的git项目

reference

https://www.git-scm.com/book/en/v2/Git-Tools-Submodules

https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97

如何是首次克隆,初始化代码需要

git clone --recurse-submodules https://github.com/chaconinc/MainProject

​ 或如果首次没有使用--recurse-submodules,那后面可以通过

git submodule initgit submodule update,进行子模块的拉取更新

如何要对子模块的代码也用克隆地址

  1. git config -f .gitmodules -e # opens editor, update URLs for your forks

  2. git submodule sync

后期从远程仓库更新submodule代码

1
git submodule update --remote

在已有项目添加子模块

1
git submodule add https://xxx.git configserver

其它

合并策略

warning: 不建议在没有为偏离分支指定合并策略时执行pull操作。
您可以在执行下一次pull操作之前执行下面一条命令来抑制本消息:

1
2
3
git config pull.rebase false # 合并(缺省策略)  
git config pull.rebase true # 变基
git config pull.ff only # 仅快进

您可以将 “git config” 替换为 “git config –global” 以便为所有仓库设置
缺省的配置项。您也可以在每次执行 pull 命令时添加 –rebase、–no-rebase,
或者 –ff-only 参数覆盖缺省设置。

推送本地离线项目到远程github

1
2
3
4
5
6
7
8
mkdir my_project
cd my_project
touch .gitignore
git init
git add .
git commit -m "Initial commit"
git remote add origin youruser@yourserver.com:/path/to/my_project.git
git push origin master

更改https协议进行推送

如果之前是使用ssh协议进行推送,现改为http协议

  1. 查看当前Git项目的远程地址

    1
    git remote -v

    该命令会列出所有已配置的远程仓库地址,并显示它们的读取和写入访问URL。示例输出如下所示:

    1
    2
    origin  https://github.com/username/repository.git (fetch)
    origin https://github.com/username/repository.git (push)

    其中,origin是远程仓库的名称,https://github.com/username/repository.git是远程仓库的地址,(fetch)(push)分别表示读取和写入访问URL。

  2. 将Git仓库的URL替换为HTTP协议的URL

    1
    git remote set-url origin http://gitlab.xxx.com/username/repository.git
  3. 然后使用以下命令进行Git push操作

后记:需要注意的是,使用HTTP协议进行Git push操作的速度可能会比使用SSH协议慢一些,因为HTTP协议需要建立TCP连接、发送HTTP请求、接收HTTP响应等过程。同时,HTTP协议的安全性也比SSH协议稍低,因此在安全性要求较高的情况下,建议使用SSH协议进行Git push操作。

Git修改.gitignore不生效

  • 在git中,如果想忽略某个文件,不让这个文件提交到版本库中,可以修改根目录中的.gitignore文件

    但有时候把某些目录或者文件加入忽略规则,发现并未生效

  • 未生效原因:.gitignore只能忽略那些原来没有被追踪(track)的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的

  • 解决方案:先把本地缓存删除(改变成未track状态),然后提交。

1
2
3
git rm -r --cached <要忽略的具体文件或者目录> 或者 git rm -r --cached . 
git add .
git commit -m "update .gitignore"
1

类型

  • int变量自增 效率问题

    1
    i++;和i += 1;形成的指令数较少,且不需要操作数栈。相对而言,i = i+1;需要至少2个操作数栈深度,并且形成的指令数较多。故,i++;和i+= 1;的效率一样,并且二者的效率都优于i = i+1;

泛型

T,E,K,V,?是这样约定的:

  • ?表示不确定的 java 类型
  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element

?和 T 的区别

img

?和 T 都表示不确定的类型,区别在于我们可以对 T 进行操作,但是对 ?不行,比如如下这种 :

1
2
3
4
5
// 可以
T t = operate();

// 不可以
?car = operate();

简单总结下:

T 是一个 确定的 类型,通常用于泛型类和泛型方法的定义,?是一个 不确定 的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。

PECS(Producer Extends Consumer Super)原则:作为生产者提供数据(往外读取)时,适合用上界通配符(extends);作为消费者消费数据(往里写入)时,适合用下界通配符(super)。

时间

在 JDK8 以后,建议使用 DateTimeFormatter 代替 SimpleDateFormat ,因为 SimpleDateFormat 是线程不安全的,而 DateTimeFormatter 是线程安全的。当然,也可以采用第三方提供的线程安全日期格式化函数,比如 apache 的 DateFormatUtils 工具类。

**对于一个好的框架,从外部来看应该具有非常简单易于使用的 API,且 API 契约明确;从内部来看的话,其应该有一个可扩展的架构,即非常容易插入用户自定义实现,因为任何框架都不能满足所有需求。 **


  • Subject

    主体,代表了当前的用户

  • SecurityManager

    安全管理器,它管理着所有Subject,相当于springmvc中的DispatcherServlet(前端控制器)

  • Realm

    域,Shiro从Realm获取安全数据(如用户、角色、权限) ,是验证主体subject的数据源

流程如图:

流程说明

  1. 应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;
  2. 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。

从以上也可以看出,Shiro 不提供维护用户 / 权限,而是通过 Realm 让开发人员自己注入。


shiro的内部结构如图:


身份验证

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。

credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。

  • 身份认证流程


授权

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

  • 授权方式编程式、注解式、jsp/gsp标签式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1 	Α 	α 	alpha a:lf 阿尔法
2 Β β beta bet 贝塔
3 Γ γ gamma ga:m 伽马
4 Δ δ delta delt 德尔塔
5 Ε ε epsilon ep`silon 伊普西龙
6 Ζ ζ zeta zat 截塔
7 Η η eta eit 艾塔
8 Θ θ theta θit 西塔
9 Ι ι iota aiot 约塔
10 Κ κ kappa kap 卡帕
11 ∧ λ lambda lambd 兰布达
12 Μ μ mu mju 缪
13 Ν ν nu nju 纽
14 Ξ ξ xi ksi 克西
15 Ο ο omicron omik`ron 奥密克戎
16 ∏ π pi pai 派
17 Ρ ρ rho rou 肉
18 ∑ σ sigma `sigma 西格马
19 Τ τ tau tau 套
20 Υ υ upsilon ju:p`sailon 宇普西龙
21 Φ φ phi fai 佛爱
22 Χ χ chi phai 西
23 Ψ ψ psi psai 普西
24 Ω ω omega o`miga 欧米伽

A filter is an object that is invoked at the preprocessing and postprocessing of a request.

  • It is mainly used to perform filtering tasks such as conversion, logging, compression, encryption and decryption, input validation etc.
  • The servlet filter is pluggable, i.e. its entry is defined in the web.xml file, if we remove the entry of filter from the web.xml file, filter will be removed automatically and we don’t need to change the servlet.

Usage of Filter

  • recording all incoming requests
  • logs the IP addresses of the computers from which the requests originate
  • conversion
  • data compression
  • encryption and decryption
  • input validation etc.

Advantage of Fliter

  • Filter is pluggable.
  • One filter don’t have dependency onto another resource.
  • Less Maintenance

Filter API

  • Filter

    For creating any filter, you must implement the Filter interface. Filter interface provides the life cycle methods for a filter.

  • FilterChain

    The object of FilterChain is responsible to invoke the next filter or resource in the chain.This object is passed in the doFilter method of Filter interface.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class MyFilter implements Filter{  
    public void init(FilterConfig arg0) throws ServletException {}

    public void doFilter(ServletRequest req, ServletResponse resp,
    FilterChain chain) throws IOException, ServletException {

    PrintWriter out=resp.getWriter();
    out.print("filter is invoked before");

    chain.doFilter(req, resp);//sends request to next resource

    out.print("filter is invoked after");
    }
    public void destroy() {}
    }

```

  • FilterConfig

Events are basically occurrence of something. Changing the state of an object is known as an event.

1
We can perform some important tasks at the occurrence of these exceptions, such as counting total and current logged-in users, creating tables of the database at time of deploying the project, creating database connection object etc.

Event classes

  • ServletRequestEvent
  • ServletContextEvent
  • ServletRequestAttributeEvent
  • ServletContextAttributeEvent
  • HttpSessionEvent
  • HttpSessionBindingEvent

Event interfaces

  • ServletRequestListener
  • ServletRequestAttributeListener
  • ServletContextListener
  • ServletContextAttributeListener
  • HttpSessionListener
  • HttpSessionAttributeListener
  • HttpSessionBindingListener
  • HttpSessionActivationListener

ServletContextEvent and ServletContextListener

  • The ServletContextEvent is notified when web application is deployed on the server.
  • If you want to perform some action at the time of deploying the web application such as creating database connection, creating all the tables of the project etc, you need to implement ServletContextListener interface and provide the implementation of its methods.

Web application > ServletContextEvent > ServletContextListener

HttpSessionEvent and HttpSessionListener

  • The HttpSessionEvent is notified when session object is changed. The corresponding Listener interface for this event is HttpSessionListener.
  • We can perform some operations at this event such as counting total and current logged-in users, maintaing a log of user details such as login time, logout time etc.

session object > HttpSessionEvent > HttpSessionListener

base64ToByte

1
2
3
4
5
6
7
8
9
String string = "SmF2YWNvZGVnZWVrcw==";
// Get bytes from string
byte[] byteArray = Base64.decodeBase64(string.getBytes());

// Print the decoded array
System.out.println(Arrays.toString(byteArray));
// Print the decoded string
String decodedString = new String(byteArray);
System.out.println(string + " = " + decodedString);

TimeConvert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//date format
import org.apache.commons.lang3.time.DateFormatUtils;
String timeStr = DateFormatUtils.format(dateDate,"yyyy-MM-dd HH:mm:ss");
Date dateTime = DateUtils.parseDate(dateTimeStr,"yyyy-MM-dd HH:mm:ss");

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

//capitalize the first letter of word
String output = input.substring(0, 1).toUpperCase() + input.substring(1);

//measure the time cost
long start = System.nanoTime();
//...
long end = System.nanoTime();
long used = end-start;
System.out.println("used:"+TimeUnit.NANOSECONDS.toMillis(used)+" ms");

Lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//stream read database   
public void testStreamRead() {
oracleSqlSessionTemplate.select("xxxx.OracleMapper.getPersonInfos", new ResultHandler() {
@Override
public void handleResult(ResultContext resultContext) {
PersonInfo personInfo = (PersonInfo) resultContext.getResultObject();
LOG.debug("result count:[{}],result info:[{}]", resultContext.getResultCount(), personInfo.getName());
}
});
}

public void testStreamRead2() {
oracleSqlSessionTemplate.select("xxxx.OracleMapper.getPersonInfos",
resultContext -> {
PersonInfo personInfo = (PersonInfo) resultContext.getResultObject();
LOG.debug("result count:[{}],result info:[{}]", resultContext.getResultCount(), personInfo.getName());
}
);
}

//iterate list
myFinalList = new ArrayList<>();
myListToParse.stream()
.filter(elt -> elt != null)
.forEach(elt -> myFinalList.add(doSomething(elt)));
//prefer
myFinalList = myListToParse.stream()
.filter(elt -> elt != null)
.map(elt -> doSomething(elt))
.collect(Collectors.toList());

thread

notify thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class Shared
{
synchronized void waitMethod()
{
Thread t = Thread.currentThread();

System.out.println(t.getName()+" is releasing the lock and going to wait");

try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}

System.out.println(t.getName()+" has been notified and acquired the lock back");
}

synchronized void notifyOneThread()
{
Thread t = Thread.currentThread();

notify();

System.out.println(t.getName()+" has notified one thread waiting for this object lock");
}
}

public class MainClass
{
public static void main(String[] args)
{
final Shared s = new Shared();

//Thread t1 will be waiting for lock of object 's'

Thread t1 = new Thread()
{
@Override
public void run()
{
s.waitMethod();
}
};

t1.start();

//Thread t2 will be waiting for lock of object 's'

Thread t2 = new Thread()
{
@Override
public void run()
{
s.waitMethod();
}
};

t2.start();

//Thread t3 will be waiting for lock of object 's'

Thread t3 = new Thread()
{
@Override
public void run()
{
s.waitMethod();
}
};

t3.start();

try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}

//Thread t4 will notify only one thread which is waiting for lock of object 's'

Thread t4 = new Thread()
{
@Override
public void run()
{
s.notifyOneThread();
}
};

t4.start();
}
}

stop thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class MyThread extends Thread
{
//Initially setting the flag as true

private volatile boolean flag = true;

//This method will set flag as false

public void stopRunning()
{
flag = false;
}

@Override
public void run()
{
//Keep the task in while loop

//This will make thread continue to run until flag becomes false

while (flag)
{
System.out.println("I am running....");
}

System.out.println("Stopped Running....");
}
}

public class MainClass
{
public static void main(String[] args)
{
MyThread thread = new MyThread();

thread.start();

try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}

//call stopRunning() method whenever you want to stop a thread

thread.stopRunning();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class MyThread extends Thread
{
@Override
public void run()
{
while (!Thread.interrupted())
{
System.out.println("I am running....");
}

System.out.println("Stopped Running.....");
}
}

public class MainClass
{
public static void main(String[] args)
{
MyThread thread = new MyThread();

thread.start();

try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}

//interrupting the thread

thread.interrupt();
}
}

try-catch-finally

  1. 不管有木有出现异常,finally块中代码都会执行**
  2. 当try和catch中有return时,finally仍然会执行
  3. finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
  4. finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
  5. 任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的。

ReentrantLock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Java program to show, how to use ReentrantLock in Java.
* Reentrant lock is an alternative way of locking
* apart from implicit locking provided by synchronized keyword in Java.
*
* @author Javin Paul
*/
public class ReentrantLockHowto {

private final ReentrantLock lock = new ReentrantLock();
private int count = 0;

//Locking using Lock and ReentrantLock
public int getCount() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " gets Count: " + count);
return count++;
} finally {
lock.unlock();
}
}

//Implicit locking using synchronized keyword
public synchronized int getCountTwo() {
return count++;
}



public static void main(String args[]) {
final ThreadTest counter = new ThreadTest();
Thread t1 = new Thread() {

@Override
public void run() {
while (counter.getCount() &lt; 6) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace(); }
}
}
};

Thread t2 = new Thread() {

@Override
public void run() {
while (counter.getCount() &lt; 6) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};

t1.start();
t2.start();

}
}
1
2
3
4
5
6
7
8
9
Output:
Thread-0 gets Count: 0
Thread-1 gets Count: 1
Thread-1 gets Count: 2
Thread-0 gets Count: 3
Thread-1 gets Count: 4
Thread-0 gets Count: 5
Thread-0 gets Count: 6
Thread-1 gets Count: 7

https://www.jianshu.com/p/49d7997ad3b7

https://blog.csdn.net/qq_33546747/article/details/53304097


WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

多个角度来理解WebService
​ 从表面上看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。
​ 我们把调用这个WebService的应用程序叫做客户端,而把提供这个WebService的应用程序叫做服务端

1
2
从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。
它定义了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。

构成WebService平台的三大技术:
​ XML+XSD,SOAP和WSDL

WebService采用HTTP协议传输数据,采用XML格式封装数据(即XML中说明调用远程服务对象的哪个方法,传递的参数是什么,以及服务对象的返回结果是什么)
WebService用XSD来作为其数据类型系统
HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC方法来调用Web Service。

SOAP协议 = HTTP协议 + XML数据格式

比喻:HTTP就是普通公路,XML就是中间的绿色隔离带和两边的防护栏,SOAP就是普通公路经过加隔离带和防护栏改造过的高速公路。

WSDL(Web Services Description Language)是基于XML的语言,用于描述Web Service及其函数、参数和返回值。

WSDL文件保存在Web服务器上,通过一个url地址就可以访问到它。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。
WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。

======================================================================================
https://www.cnblogs.com/snake-hand/archive/2013/06/09/3129915.html


Axis和CXF,这两个产品都是Apache孵化器下面的Web Service开源开发工具

CXF支持 WS-Addressing,WS-Policy, WS-RM, WS-Security和WS-I Basic Profile
Axis2不支持WS-Policy

CXF可以很好支持Spring
Axis2不能很好支持Spring

CXF只支持JAXB和Aegis。
AXIS2支持更广泛的数据并对,如XMLBeans,JiBX,JaxMe和JaxBRI和它自定义的数据绑定ADB。注意JaxME和JaxBRI都还是试验性的。AXIS2支持更广泛的数据并对,如XMLBeans,JiBX,JaxMe和JaxBRI和它自定义的数据绑定ADB。注意JaxME和JaxBRI都还是试验性的。


如何抉择:
1、如果应用程序需要多语言的支持,Axis2 应当是首选了;
2、如果应用程序是遵循Spring 哲学路线的话,Apache CXF 是一种更好的选择,特别对嵌入式的Web Services 来说;
3、如果应用程序没有新的特性需要的话,就仍是用原来项目所用的框架,比如Axis1,XFire,Celtrix或 BEA等等厂家自己的 WebServices 实现,就别劳民伤财了