欢迎来到【网页砍价源码】【snmp 源码】【emsflow源码】beng源码-皮皮网网站!!!

皮皮网

【网页砍价源码】【snmp  源码】【emsflow源码】beng源码-皮皮网 扫描左侧二维码访问本站手机端

【网页砍价源码】【snmp 源码】【emsflow源码】beng源码

2024-11-26 17:38:13 来源:{typename type="name"/} 分类:{typename type="name"/}

1.在asp中怎样通过中文名字的源码首字母来查询姓名列表
2.excel中好像有个放置猴子去射气球的游戏,请问哪里有得下啊
3.MyBatis自定义TypeHandler

beng源码

在asp中怎样通过中文名字的源码首字母来查询姓名列表

       比较简单易实现的就是你自己直接添加一个字段为明星的首字母,这样通过查询这个字段就可以实现这个功能了,源码其他的源码都是很复杂庞大的工程。。源码。源码网页砍价源码

       其他参考代码

       原理,源码使用Dictionary技术

        1.添加索引

        2.遍历词典

        <%

        Set d = CreateObject("Scripting.Dictionary")

        d.add "a",源码-

        d.add "ai",-

        d.add "an",-

        d.add "ang",-

        d.add "ao",-

        d.add "ba",-

        d.add "bai",-

        d.add "ban",-

        d.add "bang",-

        d.add "bao",-

        d.add "bei",-

        d.add "ben",-

        d.add "beng",-

        d.add "bi",-

        d.add "bian",-

        d.add "biao",-

        d.add "bie",-

        d.add "bin",-

        d.add "bing",-

        d.add "bo",-

        d.add "bu",-

        d.add "ca",-

        d.add "cai",-

        d.add "can",-

        d.add "cang",-

        d.add "cao",-

        d.add "ce",-

        d.add "ceng",-

        d.add "cha",-

        d.add "chai",-

        d.add "chan",-

        d.add "chang",-

        d.add "chao",-

        d.add "che",-

        d.add "chen",-

        d.add "cheng",-

        d.add "chi",-

        d.add "chong",-

        d.add "chou",-

excel中好像有个放置猴子去射气球的游戏,请问哪里有得下啊

       一:纸牌游戏

       启动Excel程序,源码依次点击工具栏中“工具/自定义”菜单,源码切换至“命令”标签页,源码选中左侧“类别”栏中的源码“工具”菜单,向下拖动右侧“命令”栏侧边滑块,源码找到带有纸牌图形的源码“自定义”选项(如图),将它拖至Excel工具栏中,源码点击“关闭”按钮将“自定义”对话框关闭。现在,Excel工具栏中就多了一个纸牌按钮,点击该按钮,熟悉的snmp 源码纸牌游戏界面就出现在你面前了。

       二: MicroSoft Excel 暗藏赛车游戏

       1.开启Excel之后随便开一新文档,将它『另存成Web画面 』,按下发布后再将“添加交互对象”打勾,将档案储存为car.htm(文件名可自取)。

       2.在IE中开启car.htm,你应该会看到电子表格出现在网页中央,如图1:

       图1

       3.在这个工作表中,先用PageDown键移动工作表的矩形光标直至第行,注意只能用PageDown键,然后用Tab键横向向右移动光标直至WC列,也是只能用键操作,到此,所有的准备工作已经完毕,该是调出游戏的时候了。

       4.同时按住Shift+Crtl+Alt 然后点选左上方的 Office logo 。

       5.开始玩了,如图2:

       图2

       6.玩法提示: 玩游戏的时候,被你控制的是那一辆浅蓝色的汽车,操作的主要是四个箭头按键。作用是:左右箭头可以控制汽车的方向:向上箭头可以加速, 向下的箭头减速;如果汽车运行到了夜间,可用H键打开车灯。

       绝对好玩!emsflow源码

       三:数字华容道

       '先说个简单的。大家玩过那个数字华容道吧,就是有N*N个格,有一格是空的,其他格是次序混乱的拼图或数字,游戏的目的就是利用这唯一的这个空格移动各块拼图把混乱的拼图(数字)恢复(顺序)。这里我们小游戏的目的是要把1至这个次序混乱的数字恢复从1到的顺序排列。

       '打开Excel后打开代码编写器(Alt + F),将如下代码写入模块中。程序首先是初始化。定义变量,选择4*4的空格,调整表格大小,改变单元格颜色(标示出游戏区域),然后是让1到非重复随机分布到前格空格中:

       Public Const PW = "Excelba.com" '本游戏由Excel吧bengdeng整理!

       Public Running As Boolean '用于判断游戏是否进行中,如果要中途退出或玩家需要重玩用此变量控制

       Public SRan As Range '游戏左上单元格

       Public BRan As Range '游戏空格单元格

       Public N As Integer '游戏区域大小

       Public GRan As Range '游戏区域,这里由N与SRan生成

       Public Bs As Integer '游戏步数

       Public STime As Date '游戏开始时间

       Sub GameStar()

       Dim i As Integer

       Dim ii As Integer

       Dim temp As Integer

       Dim a() As Integer

       Dim down As VbMsgBoxResult

       '判断游戏是否在运行

       If Running Then

       down = MsgBox("游戏正在进行!是xshell 源码否重玩?", vbYesNo, "提示 - " & PW)

       If down = vbNo Then Exit Sub

       End If

       Running = True

       N = 4 '设定游戏区域为4*4

       Set SRan = Range("E5") '设定游戏开始单元格为E5

       Set BRan = SRan.Offset(N - 1, N - 1) '设定游戏空单元格

       Set GRan = Range(SRan, BRan)

       '游戏区域(颜色)初始化,省略了单元格大小的调整,大家可以应该加入相应语句让游戏外观整齐

       If ActiveSheet.ProtectContents Then ActiveSheet.Unprotect Password:=PW

       GRan.ClearContents

       GRan.Interior.ColorIndex =

       '随机数数组初始化,这里是编号0到编号共个数

       For i = 0 To (N * N - 2)

       a(i) = i + 1

       Next i

       '不重复随机分布各数

       For i = N * N - 2 To 0 Step -1

       Randomize

       ii = Int(Rnd * i)

       temp = a(i)

       a(i) = a(ii)

       GRan.Item(i + 1) = a(i)

       a(ii) = temp

       Next i

       Bs = 0

       STime = Now()

       ActiveSheet.Protect Password:=PW

       End Sub

       '很明显,Excel的单元格是游戏的主角。初始化后游戏开始,逻辑很简单:玩家每单击一个单元格(产生Workbook中的SheetSelectionChange事件),游戏就判断这个格是否在游戏区域中,若是就判断上下左右4个方向是否有空格,如果有空格就把原单元格中的数传到空格中,原单元格清空(空格与原单元格交换),然后判断游戏是否结束(1到顺序排序了?),若还没有,什么都不做,等下一次单击事件发生。

       Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

       Dim down As VbMsgBoxResult

       Dim i As Integer

       If Running Then

       '所单击单元格是否就是空格

       If Len(ActiveCell) > 0 Then

       '所单击单元格是否在游戏区域

       If Not (Application.Intersect(ActiveCell, GRan) Is Nothing) Then

       '所单击单元格上下左右是否有空格

       If ((Abs(BRan.Column - ActiveCell.Column) <= 1 And BRan.row = ActiveCell.row) Or (Abs(BRan.row - ActiveCell.row) <= 1 And BRan.Column = ActiveCell.Column)) Then

       '单元格与空格交换

       If ActiveSheet.ProtectContents Then ActiveSheet.Unprotect Password:=PW

       BRan = ActiveCell

       ActiveCell.ClearContents

       Set BRan = ActiveCell

       Bs = Bs + 1

       ActiveSheet.Protect Password:=PW

       '判断游戏是否结束?

       i = 1

       Do While (i < N * N And GRan.Item(i) = i)

       i = i + 1

       Loop

       If i = N * N Then

       MsgBox "祝贺你!你成功了!" & vbCrLf & _

       "一共用了" & Bs & "步!" & vbCrLf & _

       "一共用用时" & Format(Now - STime, "h:m:s"), , PW

       Running = False

       End If

       End If

       End If

       End If

       Else

       down = MsgBox("游戏还未进行,是attack源码否开始?", vbYesNo, "提示 - " & PW)

       If down = vbYes Then GameStar

       End If

       End Sub

       四:跑跑卡丁车.xls

       网上到处可下!注:打开Excel后,若不能玩,点菜单栏上的工具→宏→安全性,将安全级别设为低,便可以玩了

       五:贪吃蛇源码

       首先要解决游戏显示的问题。对我们来说,小游戏最好的平台是Excel的工作区,由于大小可调、颜色可填的单元格操作方便,我们完全可以把它们当像素来使用。于是我们的贪吃蛇游戏就有了以单元格为基础的像素形式的显示方式了。

       其次是游戏的控制方法。在这里我摸索了好久,其中走了弯路不说,我最后的结论是在Excel中要实现按键事件的方法是引入窗体,然后在窗体中响应Keydown与Keypress事件。这样的话,既可以快速响应还可以根据情况修改对应按键。

       最后是游戏的定时问题。所有的游戏事实上都是在一个时间大循环里面定时接收输入信息更新状态的程序,我们的小游戏都不例外。老实说,我写这个游戏大部分的思考时间就浪费在如何实现游戏定时这里。Excel的VBA中与定时有关的只有onTime函数,没有其他相关函数提供了,onTime函数可以实现某一事件在指定时间发生,但只能以秒为最小单位,对我们要在一秒内更新数十次信息的小游戏不适合,我们只能另找方法。用过VB的人都知道VB控件中有个定时控件,用它来实现游戏定时是最好的,但在Excel中却没有,难道我要把VB中的定时控件移植到VBA中?这也是个很值得研究的课题,但是我想到了另外的方法。VB的程序员都知道要想VB程序发挥大作用一定离不开调用系统的API,于是我查看了系统相关API的帮助,发现系统API中实现相应功能的有settimer与killtimer函数,具体定义和用法大家可以参考相关帮助,但从字面大家都已经可以知道它们就是我们要找的东西了。那么现在的问题就是如何在vba环境下调用系统API。心想微软称vba就是office中的vb,那么在vba中调用系统API应该也与在VB中的一样。一试,呵呵,果然非虚,这微软真不是盖的(后在msdn中发现ms office vba从版本开始支持调用系统API,大家可以拓展office应用了)。

       就这样游戏输入、输出、逻辑定时的问题都解决了,我们的吃蛇游戏就仅剩下算法逻辑部分了。我们的游戏逻辑是,游戏初始化后,启动定时器。在每次定时循环中,程序分别实现蛇头移动与蛇尾移动。首先是移动蛇头,游戏判断在移动方向上蛇头下一个的位置是否为空格,若是则把这位置的空格填上颜色(蛇头移动),蛇尾移动标志设为真;如果蛇头下一个位置不是空格(即有食物),则把这位置的空格填上颜色(蛇头移动)后把蛇尾移动标志设为假。接着到蛇尾移动部分,若蛇尾移动标志为真则把蛇尾原所在单元格填回白色(蛇尾移动),并更新蛇尾位置;如果蛇尾移动标志为假,则什么都不做(蛇尾不动蛇头动,蛇身长了)。对于整个游戏来说,效率的瓶颈在于像素操作(对单元格频繁填色)。但从以上算法可以看到,在每次循环中程序只需处理蛇头及蛇尾所在单元格;如果贪吃蛇吃到食物,则只需要更新蛇头单元格。每个时间循环里较少的数据处理量实现了游戏较快的响应速度,贪吃蛇游戏在Excel中实现也有了实际意义。

       游戏还是以宏的形式实现。大家新建一个宏,输入如下代码。

       ' 熟悉VB的程序员知道首先是对调用系统API的声明

       Public Declare Function SetTimer Lib "user" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

       Public Declare Function KillTimer Lib "user" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long

       ' 定义数据结构

       Type pos_

       row As Long

       col As Long

       End Type

       Public timerset As Long ' SetTimer函数的返回值,用以标记已存在的Timer,KillTimer以此为参数销毁所标记的Timer

       Public gaming As Boolean

       Public pulsed As Boolean

       Public head_movement As Long '蛇头新移动方向标志,1、2、3、4代表右上左下

       Public tail_movement As Long '蛇尾移动方向标志,意义同上

       Public oldhead_movement As Long '蛇头旧有移动方向标志

       Dim tailmove As Boolean '蛇尾移动标志

       Dim origin_size As Long '贪吃蛇原始大小

       Public score As Long

       Dim steps As Long

       Dim clean As Boolean

       Dim sth As pos_

       Dim headrow As Long '蛇头所在行位置

       Dim headcol As Long '蛇头所在列位置

       Dim tailrow As Long '蛇尾所在行位置

       Dim tailcol As Long '蛇尾所在列位置

       Dim startpos As pos_ '贪吃蛇起始位置

       Dim color As Long

       Const left As L 5 '游戏区域左边边界

       Const right As L '游戏区域右边边界

       Const top As L 3 '游戏区域上边边界

       Const bottom As L '游戏区域下边边界

       Function main() '主函数

       gaming = False

       If Worksheets.Count < 2 Then

       ActiveWorkbook.Sheets.Add after:=Worksheets(Worksheets.Count)

       ElseIf (MsgBox("Do you want to run it in a new blank worksheet ?", vbOKCancel, "?") = vbOK) Then

       ActiveWorkbook.Sheets.Add after:=Worksheets(Worksheets.Count)

       Else

       Worksheets(Worksheets.Count).Select

       End If

       Load UserForm1 '引入窗体

       UserForm1.Show

       End Function

       Function game_initial() '游戏初始化函数

       '初始化游戏界面

       color = 5

       If Not gaming Then

       Cells.ColumnWidth = 1

       Cells.RowHeight =

       Range(Cells(top, left), Cells(top, right)).Interior.ColorIndex = 1

       Range(Cells(top + 1, left), Cells(bottom - 1, left)).Interior.ColorIndex = 1

       Range(Cells(bottom, left), Cells(bottom, right)).Interior.ColorIndex = 1

       Range(Cells(top + 1, right), Cells(bottom - 1, right)).Interior.ColorIndex = 1

       Range(Cells(top + 1, left + 1), Cells(bottom - 1, right - 1)).Font.ColorIndex = color

       End If

       '贪吃蛇初始化

       origin_size = 5

       tail_movement = 1

       head_movement = 1

       oldhead_movement = head_movement

       startpos.row = (top + bottom) \ 2 'initialized as

       startpos.col = (left + right) \ 2 'initailized as

       pulsed = False

       tailmove = True

       headrow = startpos.row

       headcol = startpos.col

       tailrow = startpos.row

       tailcol = startpos.col - origin_size + 1

       clean = True

       steps = 0

       score = 0

       For i = 0 To origin_size - 1

       Cells(startpos.row, startpos.col - i).Interior.ColorIndex = color

       Next i

       gaming = True

       '游戏初始化结束

       End Function

       Sub snake_move()

       If gaming Then

       Dim nextcol As Long

       Dim nextrow As Long

       If clean Then

       steps = steps + 1

       '贪吃蛇食物生成,这里食物的生成过程很简单,蛇每前进6步就生成一块食物

       If steps >= 6 Then

       steps = 0

       Randomize

       sth.row = Int((bottom - top) * Rnd) + top + 1

       Randomize

       sth.col = Int((right - left) * Rnd) + left + 1

       Do While sth.row >= bottom

       sth.row = sth.row - (bottom - top) + 1

       Loop

       Do While sth.col >= right

       sth.col = sth.col - (right - left) + 1

       Loop

       Cells(sth.row, sth.col) = "*"

       clean = False

       End If

       End If

       ''''''蛇头移动部分

       tailmove = True

       If oldhead_movement <> head_movement Then

       If Abs(oldhead_movement - head_movement) <> 2 Then

       oldhead_movement = head_movement

       Cells(headrow, headcol) = head_movement '当方向改变时在蛇头当前单元格记下前进方向,待蛇尾运行至此时可以按正确方向前进。本来应该用个数组记录,但我懒得再琢磨了。

       End If

       End If

       Select Case oldhead_movement

       Case 1 'right

       nextrow = headrow

       nextcol = headcol + 1

       Case 2 'up

       nextcol = headcol

       nextrow = headrow - 1

       Case 3 'left

       nextrow = headrow

       nextcol = headcol - 1

       Case 4 'down

       nextcol = headcol

       nextrow = headrow + 1

       End Select

       '看是否超出游戏区域了。

       If nextcol = left Then

       nextcol = right - 1

       ElseIf nextcol = right Then

       nextcol = left + 1

       End If

       If nextrow = top Then

       nextrow = bottom - 1

       ElseIf nextrow = bottom Then

       nextrow = top + 1

       End If

       If Cells(nextrow, nextcol).Interior.ColorIndex = color Then '蛇头碰到蛇身了,游戏结束

       Call game_over: Exit Sub

       End If

       If Cells(nextrow, nextcol) = "*" Then

       Call score_

       Cells(nextrow, nextcol).ClearContents

       End If

       Cells(nextrow, nextcol).Interior.ColorIndex = color

       headrow = nextrow

       headcol = nextcol

       ''''''蛇尾移动部分

       If tailmove Then

       Select Case tail_movement

       Case 1 'right

       nextrow = tailrow

       nextcol = tailcol + 1

       Case 2 'up

       nextrow = tailrow - 1

       nextcol = tailcol

       Case 3 'left

       nextrow = tailrow

       nextcol = tailcol - 1

       Case 4 'down

       nextcol = tailcol

       nextrow = tailrow + 1

       End Select

       If nextcol = left Then

       nextcol = right - 1

       ElseIf nextcol = right Then

       nextcol = left + 1

       End If

       If nextrow = top Then

       nextrow = bottom - 1

       ElseIf nextrow = bottom Then

       nextrow = top + 1

       End If

       If Cells(nextrow, nextcol) <> 0 Then

       If (Asc(Cells(nextrow, nextcol)) <> ) Then

       tail_movement = Cells(nextrow, nextcol)

       Cells(nextrow, nextcol).ClearContents

       End If

       End If

       Cells(tailrow, tailcol).Interior.ColorIndex = 0

       tailrow = nextrow

       tailcol = nextcol

       End If

       End If

       End Sub

       Function game_over()

       If timerset <> 0 Then

       timerset = KillTimer(0, timerset)

       pulsed = False

       End If

       If MsgBox("Game over...temporarily. Try again?", vbOKCancel, "?") = vbOK Then

       Range(Cells(top + 1, left + 1), Cells(bottom - 1, right - 1)).Interior.ColorIndex = 0

       Range(Cells(top + 1, left + 1), Cells(bottom - 1, right - 1)).ClearContents

       Call game_initial

       Else

       Cells.ClearContents

       Cells.Interior.ColorIndex = 0

       gaming = False

       SendKeys "%{ F4}" '这句很关键,当引入窗体后要在程序中退出窗体就要用Alt+F4

       End If

       End Function

       Function score_()

       clean = True

       score = score +

       tailmove = False

       UserForm1.Label2.Caption = "Now you have the score of " + Str(score)

       End Function

       上边是主程序(宏)部分,以下是窗体代码部分。在工程中引入用户窗体,名为UserForm1,拖入两个label控件名为Label1、2,再在窗体属性窗口调整好窗体在Excel中出现的位置。完成后在窗体代码窗口键入如下代码:

       Private Sub UserForm_Initialize() '窗体初始化事件

       Call game_initial

       If gaming Then

       UserForm1.Label1.Caption = "NO PLAY , NO GAME"

       UserForm1.Label2.Caption = "Arrow keys to move. P key to pause the game E key to end the game"

       Else

       UserForm1.Label1.Caption = "Something happened !"

       End If

       End Sub

       Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer) '响应窗体KeyDown事件

       If gaming Then

       If Not pulsed Then

       pulsed = True

       timerset = SetTimer(0, 0, , AddressOf snake_move) '启动定时器,这里时间间隔为毫秒,大家可以加入一些代码用来实现越来越快的游戏速度

       UserForm1.Label2.Caption = "Arrow keys to move. P key to pause the game E key to end the game"

       End If

       Select Case KeyCode

       Case vbKeyUp

       head_movement = 2

       Case vbKeyDown

       head_movement = 4

       Case vbKeyLeft

       head_movement = 3

       Case vbKeyRight

       head_movement = 1

       Case vbKeyP '这里是通过销毁定时器实现游戏暂停

       If timerset <> 0 Then

       timerset = KillTimer(0, timerset)

       pulsed = False

       End If

       UserForm1.Label2.Caption = "Game paused. Any key to resume. "

       Case vbKeyE

       Call game_over

       End Select

       End If

       End Sub

       Private Sub UserForm_Terminate() '窗体销毁事件,这里是通过主程序发出Alt+F4按键事件引发

       If timerset <> 0 Then

       timerset = KillTimer(0, timerset)

       pulsed = False

       End If

       MsgBox ("You have finished the game with the score of " + Str(score))

       End Sub

       不过还没完,我们要找个地方启动整个程序。在工作表sheet1中找个地方拖入一个按钮用作总开关,名为CommandButton1,双击进入代码编写状态,键入

       Private Sub CommandButton1_Click()

       Call main

       End Sub

MyBatis自定义TypeHandler

       MyBatis自定义TypeHandler1什么是TypeHandler

       TypeHandler根据字面意思即为类型处理器

       引用官方文档的描述:MyBatis在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,都会用类型处理器将获取到的值以合适的方式转换成Java类型

       MyBatis存在一些默认的类型处理器,可参考官方文档

2为什么要使用TypeHandler

       在开发过程中,当默认的TypeHandler无法满足需求时,例如遇到MyBatis不支持的数据类型或需要特殊处理的类型转换,便需要自己定制对应的TypeHandler

       笔者会在下面的代码实现中完成如下几种情况的TypeHandler:

       逗号分隔保存在数据库中的数据,在对应的Java类中为数组

       自定义枚举

3如何自定义TypeHandler

       MyBatis提供了接口org.apache.ibatis.type.TypeHandler和类org.apache.ibatis.type.BaseTypeHandler

       官方文档给出的示例为继承BaseTypeHandler,笔者在这里也使用这种方式

       先来观察一下官方的StringTypeHandler:

publicclassStringTypeHandlerextendsBaseTypeHandler<String>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,Stringparameter,JdbcTypejdbcType)throwsSQLException{ ps.setString(i,parameter);}@OverridepublicStringgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ returnrs.getString(columnName);}@OverridepublicStringgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ returnrs.getString(columnIndex);}@OverridepublicStringgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ returncs.getString(columnIndex);}}

       方法名称和代码都简洁明了,观察可知,只需要完成四个方法的覆盖,即可实现自定义TypeHandler

3.1逗号分隔字符串转数组

       假设用户表t_user设计如下:

idusernametags1adminadmin,user

       对应的Java类为:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}

       tags属性在数据库中用逗号分隔的字符串保存,但User类对应的属性为String数组

       可以创建StringArrayTypeHandler来解决类型转换的问题:

publicclassStringArrayTypeHandlerextendsBaseTypeHandler<String[]>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementpreparedStatement,inti,String[]strings,JdbcTypejdbcType)throwsSQLException{ preparedStatement.setString(i,StringUtils.join(strings,","));}@OverridepublicString[]getNullableResult(ResultSetresultSet,Strings)throwsSQLException{ returnconvert(resultSet.getString(s));}@OverridepublicString[]getNullableResult(ResultSetresultSet,inti)throwsSQLException{ returnconvert(resultSet.getString(i));}@OverridepublicString[]getNullableResult(CallableStatementcallableStatement,inti)throwsSQLException{ returnconvert(callableStatement.getString(i));}/***将查询值转换为数组**@paramvalue查询值,String*@return转换结果,String[]*/privateString[]convert(Stringvalue){ returnStringUtils.isEmpty(value)?newString[0]:value.split(",");}}3.2自定义枚举

       如何创建包含中文名称的枚举,可以参考MyBatis中使用Java类与枚举

       先创建工具类用于根据code获取枚举实体:

publicclassValueNameEnumUtils{ privateValueNameEnumUtils(){ }publicstatic<EextendsValueNameEnum>EvalueOf(Class<E>enumClass,intvalue){ E[]enumConstants=enumClass.getEnumConstants();for(Ee:enumConstants){ if(e.getValue()==value){ returne;}}returnnull;}}

       和3.1中的情况不同,枚举的具体类型是不确定,所以我们要使用泛型的方式处理TypeHandler

       创建ValueNameEnumTypeHandler:

publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}}

       泛型虽然名之为泛,但在编译过程中实际会发生类型擦除

       总之,对于泛型TypeHandler,我们需要声明一个用来标识具体类型的属性privatefinalClass<E>type和创建对应的构造函数publicValueNameEnumTypeHandler(Class<E>type)

       接下来和3.1中的一致,重写四个方法:

publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}@OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,ValueNameEnumparameter,JdbcTypejdbcType)throwsSQLException{ ps.setInt(i,parameter.getValue());}@OverridepublicEgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ intcode=rs.getInt(columnName);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ intcode=rs.getInt(columnIndex);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ intcode=cs.getInt(columnIndex);returncs.wasNull()?null:valueOf(code);}/***根据枚举值返回枚举示例**@paramcode枚举值*@return枚举实例*/privateEvalueOf(intcode){ try{ returnValueNameEnumUtils.valueOf(type,code);}catch(Exceptionex){ thrownewIllegalArgumentException("Cannotconvert"+code+"to"+type.getSimpleName()+"bycodevalue.",ex);}}}

       完成上述代码直接启动,会抛出异常:Unabletofindausableconstructorforclasscn.houtaroy.springboot.common.MyBatis.handler.ValueNameEnumTypeHandler

       产生异常的源码如下:

public<T>TypeHandler<T>getInstance(Class<?>javaTypeClass,Class<?>typeHandlerClass){ //未指定JavaType,此处为falseif(javaTypeClass!=null){ try{ Constructor<?>c=typeHandlerClass.getConstructor(Class.class);return(TypeHandler<T>)c.newInstance(javaTypeClass);}catch(NoSuchMethodExceptionignored){ //ignored}catch(Exceptione){ thrownewTypeException("Failedinvokingconstructorforhandler"+typeHandlerClass,e);}}try{ //此处抛出异常Constructor<?>c=typeHandlerClass.getConstructor();return(TypeHandler<T>)c.newInstance();}catch(Exceptione){ thrownewTypeException("Unabletofindausableconstructorfor"+typeHandlerClass,e);}}

       报错的原因直白,没有找到ValueNameEnumTypeHandler的构造函数

       首先我们要了解下Java类构造函数的机制:如果定义了构造函数,则使用定义,否则默认生成空构造函数

       在3.1中的StringArrayTypeHandler,我们没有定义构造函数,自动生成空构造函数,typeHandlerClass.getConstructor()不会抛出异常

       但ValueNameEnumTypeHandler定义了一个构造函数ValueNameEnumTypeHandler(Class<E>type),且没有指定JavaType,typeHandlerClass.getConstructor()自然抛出异常

       解决方法有两种:

       创造空的构造函数

       指定JavaType

       笔者推荐第二种,因为第一种方式枚举类属性type会产生NPE(空指针异常),MyBatis官方也我们提供了注解@MappedTypes用于指定JavaType:

@MappedTypes(ValueNameEnum.class)publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ //...}4如何使用TypeHandler

       在上一章节中,我们完成了编码实现自定义TypeHandler,但完成的TypeHandler还没办法进行使用,需要手动进行配置

       有两种配置方式:局部使用和全局使用

       以StringArrayTypeHandler举例:

4.1局部使用

       在ResultMap中使用:

<resultMapid="UserResultMap"type="cn.houtaroy.springboot.common.system.model.User"><idcolumn="id"property="id"/><resultcolumn="tags"property="tags"typeHandler="cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler"/></resultMap>

       在语句中使用:

updatet_usersettags=#{ tags,typeHandler=cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler}4.2全局使用

       使用配置文件指定handler包名:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}0

       注意,此配置类型为String,只能配置一个包,推荐使用下面的方式

       手写配置类:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}1

       StringArrayTypeHandler不适合全局配置,它会在全部JavaType为String[]的属性上使用

5拓展阅读

       MyBatis3官方文档中TypeHandler内容:mybatis–MyBatis3|配置

       网上搜索的在SpringBean声明周期中进行全局配置:Mybatis自定义全局TypeHander_chuobenggu的博客-CSDN博客