移动办公OA系统
好久没有更新文章了,总觉得心里空空的,最近由于工作的原因,没有来的及及时更新,总感觉应该把学习到的东西做个记录,供大家学习,也供自己复习,温故而知新。今天趁着周末休息时间,把自己最近在公司的做的项目做一个总结。由于是刚入职不久,进公司负责的项目内容也很少,主要还是以学习为主。
一、项目介绍
某银行移动办公系统,简称移动OA,是我进公司参与的第一个项目,主要负责的是java后台接口的开发,该系统涉及iOS,android,pad三个前台页面,后台就是为这三个客户端提供公共的接口,根据业务需要,以json格式传递过来的数据在后台进行处理,然后返回到前台进行展示。我们项目组负责的是OA里面的一个小项目-督办,该项目要实现银行项目申报、催促、进度查看、项目再分解等一些功能。根据页面展示需要,我完成了一下几个接口的开发,其中包括一些常用的查找功能和图片压缩下载。
在介绍接口实现之前,有必要把自己学到的json解析再分析一遍,之前接触啊到的json格式的的字符串数据量很小,但在实际项目中数据量是如此之大,面对如此大的数据量,我也曾迷茫过,怎么解析是个问题,后来在项目经理的帮助和自己的努力下,终于完成了json解析这个工具类的开发,我觉的这个类可以应用到很多项目中,只要是涉及到json的地方都可以。
json解析代码如下:
/**
* 将json转化成map
* @param json
* @return
* @date 2017年2月25日
* @return Map<String,Object>
* @author 我心自在
*/
public static Map<String, Object> json2Map(Object json){
if(json.equals("null")){
return null;
}
JSONObject object = JSONObject.fromObject(json);
Map map = new HashMap();
Iterator it = object.keys();
while (it.hasNext()) {
String key = (String)it.next();
String value = object.getString(key);
if (JSONUtils.isObject(object.get(key))) {
map.put(key, json2Map(value));
} else if (JSONUtils.isArray(object.get(key))) {
List list = new ArrayList();
JSONArray jArray = JSONArray.fromObject(value);
for (int i = 0; i < jArray.size(); i++) {
if(JSONUtils.isObject(jArray.get(i)) ){
list.add(json2Map(jArray.get(i)));
}else if ( JSONUtils.isArray(jArray.get(i))){
list.add(json2List(jArray.get(i)));
}else {
list.add(jArray.get(i));
}
}
map.put(key, list);
} else {
map.put(key, ConvertUtil.obj2Str(object.get(key)));
}
}
return map;
}
//下面是ConvertUtil中的部分代码,下面的方法将Object转化为String
public static String obj2Str(Object obj) {
return obj == null ? null : obj.toString();
}
下面适用于json里面带数组的:
/**
* 用于 JSON里面带数组的
* @param json
* @return
*/
public static Map<String, Object> jsonArray2Map(Object json){
// if(StringUtils.startsWith(json, "{") && StringUtils.endsWith(json, "}")){
// json = "["+json+"]";
// }
JSONArray jsonArray = JSONArray.fromObject(json);
JSONObject object = jsonArray.getJSONObject(0);
Map map = new HashMap();
Iterator it = object.keys();
while (it.hasNext()) {
String key = (String)it.next();
String value = object.getString(key);
if (JSONUtils.isObject(object.get(key))) {
map.put(key, json2Map(value));
} else if (JSONUtils.isArray(object.get(key))) {
List list = new ArrayList();
JSONArray jArray = JSONArray.fromObject(value);
for (int i = 0; i < jArray.size(); i++) {
if(JSONUtils.isObject(jArray.get(i)) ){
list.add(json2Map(jArray.get(i)));
}else if ( JSONUtils.isArray(jArray.get(i))){
list.add(json2List(jArray.get(i)));
}else {
list.add(jArray.get(i));
}
}
map.put(key, list);
} else {
map.put(key, ConvertUtil.obj2Str(object.get(key)));
}
}
return map;
}
二、接口的开发
2.1 接口一:左侧菜单显示
该接口主要实现的功能是:将json传递过来的数据到展示到前台页面,主要是左侧菜单的三个按钮。
代码如下:
public class LeftMenuListServlet extends HttpServlet {
private static final long serialVersionUID = -169633978370129408L;
private Logger logger = Logger.getLogger(this.getClass());
private SuperviseService superviseService = (SuperviseService) ApplicationContextProvider.getBean("superviseService"); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// response.setContentType("application/x-www-form-urlencoded");
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
// //获取入参
String loginUserId = ConvertUtil.obj2Str(request.getSession(true).getAttribute(Current.SESSION_KEY_USER_ID)); MDC.put("user", loUserId);
MDC.put("sessionid", request.getSession().getId());
MDC.put("starttime", System.currentTimeMillis()); String opCode = "code_0001_0018_0001";
MDC.put("opcode", opCode); ResultJson resultJson = new ResultJson(); try {
String json = request.getParameter("json");
if (StringUtils.isBlank(json)) {
resultJson.setEc(CurrencyVariable.EC_PARAMETER_EXCEPTION);
resultJson.setEm(CurrencyVariable.EM_PARAMETER_EXCEPTION);
} else {
// 设置入参
Map jsonMap = JsonUtil.json2Map(json);
Map dataMap = (Map) jsonMap.get("data");
String bottomTab = (String) dataMap.get("bottomTab");
String headerTab = (String) dataMap.get("headerTab");
Object currentUserId = loginUserId;
logger.info("code_0001_0018_0002");
logger.info("\t currentUserId = " + currentUserId); resultJson = superviseService.leftMenulist(opCode, loginUserId, bottomTab,headerTab);
resultJson.setOpCode(opCode);
}
} catch (Exception e) {
logger.error("参数异常 ", e);
resultJson.setEc(CurrencyVariable.EC_PARAMETER_EXCEPTION);
resultJson.setEm(CurrencyVariable.EM_PARAMETER_EXCEPTION);
}
String newsResultJson = new GsonBuilder().serializeNulls().create().toJson(resultJson); logger.info(opCode + " newsResultJson==" + newsResultJson);
response.getOutputStream().write(newsResultJson.getBytes("UTF-8"));
//业务逻辑结束。。。
MDC.put("endtime", System.currentTimeMillis());//请求结束后put
// logger.info("操作结果:"+resultJson.getEc());
logger.log(SeriousLogger.SERIOUS_LEVEL, "操作结果:" + resultJson.getEc());
}
} //service方法如下:
@Override
public ResultJson leftMenulist(String opCode, String loginId,
String bottomTab, String headerTab) {
CloseableHttpClient httpClient = getHttpClient();
ResultJson resultJson = new ResultJson();
resultJson.setOpCode(opCode);
// resultJson.setData(jsonObject.get("data"););
CloseableHttpResponse httpResponse = null;
HttpPost post = new HttpPost(SUPERWISE_HOST + LEFT_MENU_LIST_PATH);
log.info(post.getURI());
List<NameValuePair> list = new ArrayList<NameValuePair>(); // 封装入参
list.add(new BasicNameValuePair("bottomTab", bottomTab));
list.add(new BasicNameValuePair("loginId", loginId));
list.add(new BasicNameValuePair("headerTab", headerTab)); // 重写ec,em
Common.util(httpClient, resultJson, httpResponse, post, list); return resultJson;
}
这里解释一下opCode。该项目的设计思想是通过OpCode来访问servlet,提高访问速度,有利于后期项目的维护,具体的配置在web.xml中可见:
首先定义opcode使之指向要访问的servlet如:
//左侧菜单
public static final String code_0001_0001 = "/mobileoa/web/servlet/dd/LeftMListServlet.do";
然后通过反射的方式加载此类
static{
try{
Class<?> c = Class.forName("com.mobileoa.util.ForwardCtrlVariable");
Field[] fields = c.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
String m = Modifier.toString(fields[i].getModifiers());
if (m != null && m.indexOf("final") > -1 && !("map".equals(fields[i].getName()))) {
map.put(fields[i].getName(), (String) fields[i].get(String.class));
}
}
}catch (ClassNotFoundException e){
log.error("ForwardCtrlVariable:",e);
}catch (IllegalArgumentException e){
log.error("ForwardCtrlVariable:",e);
}catch (IllegalAccessException e){
log.error("ForwardCtrlVariable:",e);
}
获得opcode值,从而访问servlet,web.xml中的配置如下:
<servlet>
<servlet-name>dubanLeftMenuListServlet</servlet-name>
<servlet-class>com.thitect.middletier.mobileoa.web.servlet.dd.LeftMListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ddLeftMenuListServlet</servlet-name>
<url-pattern>/mobileoa/web/servlet/dd/LeftMListServlet.do</url-pattern>
</servlet-mapping>
Common中util方法主要是对http请求进行了封装,关于http请求的实现方法,参见文章:http://www.cnblogs.com/10158wsj/p/6767209.html
public class Common {
private static final Logger log = Logger.getLogger(Common.class);
static ResultJson util(CloseableHttpClient httpClient, ResultJson resultJson, CloseableHttpResponse httpResponse, HttpPost post, List<NameValuePair> list) {
try {
UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(list, "UTF-8");
post.setEntity(uefEntity);
httpResponse = httpClient.execute(post);
HttpEntity entity = httpResponse.getEntity();
String s = EntityUtils.toString(entity); JSONObject jsonObject = JSONObject.fromObject(s);
log.info(jsonObject);
Object result = jsonObject.get("data");
resultJson.setData(result);
String ec = (String) jsonObject.get("ec");
if (ec.equals("0001")) {
resultJson.setEc(CurrencyVariable.EC_DUBAN_NOEXIST);
resultJson.setEm(CurrencyVariable.EM_DUBAN_NOEXIST);
}
if (ec.equals("0002")) {
resultJson.setEc(CurrencyVariable.EC_DUBAN_EXCEED);
resultJson.setEm(CurrencyVariable.EM_DUBAN_EXCEED);
}
if (ec.equals("0003") || ec.equals("0005")) {
resultJson.setEc(CurrencyVariable.EC_DUBAN_DBERROR);
resultJson.setEm(CurrencyVariable.EC_DUBAN_DBERROR);
}
if (ec.equals("0004")) {
resultJson.setEc(CurrencyVariable.EC_DUBAN_EXCEPTION);
resultJson.setEm(CurrencyVariable.EC_DUBAN_EXCEPTION);
} EntityUtils.consume(entity);
if (ec.equals("0000")) {
resultJson.setEc(CurrencyVariable.EC_SUCESS);
resultJson.setEm(CurrencyVariable.EM_SUCESS);
resultJson.setData(result); }
} catch (Exception e) {
e.printStackTrace();
resultJson.setEc(CurrencyVariable.EC_RUNTIME_EXCEPTION);
resultJson.setEm(CurrencyVariable.EM_RUNTIME_EXCEPTION);
} finally {
Common.CloseableHttpResponse(httpResponse);
Common.CloseableHttpClient(httpClient);
} return resultJson;
}
private static void CloseableHttpResponse(CloseableHttpResponse httpResponse) {
if (httpResponse != null) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} private static void CloseableHttpClient(CloseableHttpClient client) {
if (client != null) {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
至此,完成了第一个接口的开发,主要的实现就是这样,后面还陆续写了几个这种类型接口的开发,个人认为这几个接口大同小异,没有必要一一罗列,如图所示:
2.2接口二:图片压缩功能
督办项目中,有一些文件信息十一图片的形式给出的,这就要求前端打开的图片的速度要快,用户体验要好,由于之前没有做图片压缩,导致打开图片事件较长且耗费流量,所以为了实现用户体验,有必要对图片做一下压缩,压缩之后以流的方式进行下载,这个方法是写在action中的也就是struts框架。实现代码如下:
/**
* 查看流程意见图片
*/
public void showNodeOpinionPic(){
String picURL = request.getParameter("pic_url");
log.info("流程框架页面:ProcBaseForm_正文表单:查看流程处理意见图片=" + picURL);
String kmURL = this.getKMHttpUrl();
String url=kmURL+picURL;
String fdId = getParamFormUrl(url);
logger.info("fdId=" + fdId);
String loginUserId = this.getUserId();
logger.info("loginUserId=" + loginUserId);
InputStream ins = null;
BufferedInputStream bis = null;
OutputStream out = null;
HttpServletResponse response = ServletActionContext.getResponse(); List filePathResultList = oaImageReduceService.getImageList(fdId, url,request); try {
if (filePathResultList != null && filePathResultList.size() > 0) {
// 下载
Map<String, Object> filePathMap = (Map) filePathResultList.get(0);
logger.info("filePathMap===" + filePathMap);
String filePath = (String) filePathMap.get("file_path");
if (!filePath.contains(File.separator) && !filePath.contains("/")) {
filePath = auditDownloadService.getFileNameByAuditCode(
loginUserId, filePath);
}
logger.info("filePath===" + filePath);
if (StringUtils.isNotEmpty(filePath)) {
File file = new File(filePath);
if (file.exists()) {
long p = 0L;
long toLength = 0L;
long contentLength = 0L;
int rangeSwitch = 0; // 0,从头开始的全文下载;1,从某字节开始的下载(bytes=27000-);2,从某字节开始到某字节结束的下载(ex:bytes=27000-39000)
long fileLength;
String rangBytes = "";
fileLength = file.length();
logger.info("fileLength Value = " + fileLength);
ins = new FileInputStream(file);
bis = new BufferedInputStream(ins);
response.reset();
response.setHeader("Accept-Ranges", "bytes");
String range = request.getHeader("Range");
logger.info("Range's Value = " + range);
if (range != null && range.trim().length() > 0
&& !"null".equals(range)) {
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
rangBytes = range.replaceAll("bytes=", "");
if (rangBytes.endsWith("-")) { // bytes=270000-
rangeSwitch = 1;
p = Long.parseLong(rangBytes.substring(0,
rangBytes.indexOf("-")));
contentLength = fileLength - p; // 客户端请求的是270000之后的字节(包括bytes下标索引为270000的字节)
} else { // bytes=270000-320000
rangeSwitch = 2;
String temp1 = rangBytes.substring(0,
rangBytes.indexOf("-"));
String temp2 = rangBytes.substring(
rangBytes.indexOf("-") + 1,
rangBytes.length());
p = Long.parseLong(temp1);
toLength = Long.parseLong(temp2);
contentLength = toLength - p + 1; // 客户端请求的是270000-320000之间的字节
}
} else {
contentLength = fileLength;
}
// 如果设设置了Content-Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。
// Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
//response.setHeader("Content-Length",new Long(contentLength).toString());
// 断点开始
// 响应的格式是:
// Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
if (rangeSwitch == 1) {
String contentRange = new StringBuffer("bytes ")
.append(new Long(p).toString()).append("-")
.append(new Long(fileLength - 1).toString())
.append("/")
.append(new Long(fileLength).toString())
.toString();
response.setHeader("Content-Range", contentRange);
bis.skip(p);
} else if (rangeSwitch == 2) {
String contentRange = range.replace("=", " ") + "/"
+ new Long(fileLength).toString();
response.setHeader("Content-Range", contentRange);
bis.skip(p);
} else {
String contentRange = new StringBuffer("bytes ")
.append("0-").append(fileLength - 1)
.append("/").append(fileLength).toString();
response.setHeader("Content-Range", contentRange);
}
String fileName = file.getName();
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition","attachment;filename=" + fileName);
out = response.getOutputStream();
int n = 0;
long readLength = 0;
int bsize = 1024;
byte[] bytes = new byte[bsize];
if (rangeSwitch == 2) {
// 针对 bytes=27000-39000 的请求,从27000开始写数据
while (readLength <= contentLength - bsize) {
n = bis.read(bytes);
readLength += n;
out.write(bytes, 0, n);
}
if (readLength <= contentLength) {
n = bis.read(bytes, 0,(int) (contentLength - readLength));
out.write(bytes, 0, n);
}
} else {
while ((n = bis.read(bytes)) != -1) {
out.write(bytes, 0, n);
}
}
} else {
logger.info("文件不存在!");
}
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 业务处理结束
if (bis != null) {
try {
bis.close();
} catch (Exception e2) {
}
}
if (ins != null) {
try {
ins.close();
} catch (Exception e2) {
}
}
if (out != null) {
try {
out.flush();
out.close();
} catch (Exception e2) {
}
}
} /**
* 从url中获取fdId
*/
private static String getParamFormUrl(String url) {
String fdId = "";
if (StringUtils.isEmpty(url)) {
fdId = null;
}
String[] urlArr = url.split("\\?");
if (urlArr == null || urlArr.length == 0) {
fdId = null;
}
for (int i = 0; i < urlArr.length; i++) {
if (urlArr[i].contains("FCheckbox=")) {
String[] params = urlArr[i].split("\\/");
for (int j = 0; j < params.length; j++) {
if (params[j].endsWith(".jpg")) {
fdId = params[j].replace(".jpg", "");
}
}
}
}
return fdId;
}
//service部分代码
@Override
@Transactional
public List getImageList(String fdId, String url, HttpServletRequest request) {
logger.info("services param[fdId="+ fdId + ", url=" + url+ "]");
List markList = fileDao.findFileByExtendMark(fdId);
logger.info("markList="+ markList);
byte[] fileByte = null;
String fileNameTemp = null;
if(markList == null || markList.size() == 0){
fileByte = this.getImageFromURLNew1(url);
fileNameTemp = this.getNewPicName(fileByte, url);
logger.info("生成图片名称"+fileNameTemp);
} else {
fileNameTemp = (String)((Map)markList.get(0)).get("file_path");
logger.info("从数据库获取图片信息:" + fileNameTemp);
} List list = fileDao.findChildFileNameByFileName(fileNameTemp, "source");
logger.info("fileDao.findChildFileNameByFileName(fileNameTemp, 'source')"+list);
if (list == null || list.size() == 0) {
list = postfixFileConvertService.postfixConvert(fileNameTemp, CurrencyVariable.FILE_TYPE_SOURCE_TO_IMAGE, true, fileByte, null, null, request, CurrencyVariable.PORTAL, fdId);
} else {
list = postfixFileConvertService.postfixConvert(fileNameTemp, CurrencyVariable.FILE_TYPE_SOURCE_TO_IMAGE, true, null, null, null, request, CurrencyVariable.PORTAL, fdId);
}
return list;
}
这段代码基本完成了图片压缩功能的实现,另外通过设置http请求告诉浏览器以流的方式下载图片并显示到前台页页面。
三、总结
这是从学校毕业毕业工作以来,真正意义上接触到的企业大项目,该项目主要的架构就是Spring+Struts+Hibernate,另外还有部分业务的实现用的是Servlet,其实struts本身就是一个大大的Servlet,只不过是更好的对Servlet进行了封装,并且能够更好的实现MVC模式。通过该项目,大大的增加了企业项目的开发经验,熟悉了很多开发工具的使用,本项目采用的是Spring-tools-suitIDE,目的是能够更好的使用Spring。熟悉了代码管理工具SVN的使用,进一步熟悉了开发服务器Weblogic的使用,在linux环境下部署、开发javaWEB项目。
写这篇博文的目的就是及时把自己的项目经验写出来与大家共勉,也为增加自己的开发经验,进一步熟悉企业项目的开发流程,开发特点。
移动办公OA系统的更多相关文章
- 使用 asp.net mv4开发企业级办公OA
大家好!这是我第一次写asp.net 开发笔记,哪里写的不好,请见谅! 本程序是一个在线办公(OA)系统 B/S项目: 项目开发环境:Microsoft Visual Studio 2012 + Sq ...
- OA系统权限管理设计(转载)
不论什么系统都离不开权限的管理,有一个好的权限管理模块,不仅使我们的系统操作自如,管理方便,也为系统加入亮点. l 不同职责的人员,对于系统操作的权限应该是不同的.优秀的业务系统,这是 ...
- 《华油能源OA系统数据同步和扩展的设计与实现_张宇峰》阅读笔记
为什么我会找到这篇论文? 华油能源集团拥有多套信息化软件系统,每个用户需要登录操作多个软件系统,记住多个系统的用户名.密码,需要不停的切换到每个系统,查看是否有需要进行的工作:管理员更是疲于每天对各个 ...
- OA系统在实际应用中可发挥出的协同应用价值
OA软件引进国内已有二十多年,早期的OA软件更多地是扮演一个"文秘"的角色,只进行一些基本的行政事务处理,创造的价值不大.但随着OA软件理论和技术的日趋成熟,OA软件摆脱了原有的局 ...
- 浅谈OA系统与Portal门户的区别
随着社会信息化的发展与进步,OA办公自动化软件打破了传统复杂的办公方式,使各个行业实现了高效的无纸化办公.由此一来OA快速成长为继财务软件.ERP软件之后的第三大管理软件.随着企业信息化系统的不断增多 ...
- OA系统高性能解决方案(史上最全的通达OA系统优化方案)
序: 这是一篇针对通达OA系统的整体优化方案,文档将硬件.网络.linux操作系统.程序本身(包括web和数据库)以及现有业务有效结合在一起,进行了系统的整合优化.该方案应用于真实生产环境,部署完成后 ...
- 通达OA系统myisam转innodb引擎
OA系统切换到linux环境后,性能提升了2-3倍左右,随着公司的发展壮大,办公人员也会越来越多,当人数达到一定数量级别时如1500在线人数已无法支撑公司业务,就需要对系统进行性能提升优化. 当前OA ...
- OA系统权限管理设计方案【转】
l 不同职责的人员,对于系统操作的权限应该是不同的.优秀的业务系统,这是最基本的功能. l 可以对“组”进行权限分配.对于一个大企业的业务系统来说,如果要求管理员为其下员工逐一分配系统操作权限的话,是 ...
- 分享泛微公司OA系统用于二次开发的sql脚本
本单位用的oa系统就是泛微公司的oa协同办公平台,下面是我对他进行二次开发统计用到的写数据库脚本,只做开发参考使用,对于该系统的二次开发技术交流可以加我q:2050372586 [仪表盘]格式sql编 ...
随机推荐
- ASP.NET Cookie和Session
Cookie和Session C#在服务器,JS在客户端 客户端验证不能代替服务端验证 Http HTTP属于应用层,HTTP 协议一共有五大特点:1.支持客户/服务器模式;2.简单快速;3.灵活;4 ...
- SQL Server 数据库连接方法
我们用c#写ado或者是asp,都需要连接数据库来读写数据,今天我们就来总结一下数据库连接都有哪些方法. 首先我们就写最直接的方法,在事件中直接连接.(在这里就用WEB页面来展示) 首先我们建立web ...
- css写出三角形(兼容IE)
css写出三角形 利用css写三角形,兼容IE7 .arrow-up { width:0px; height:0px; border-left:10px solid transparent; bo ...
- 使用JavaEE的ServerAuthModule模块和web.xml进行相应配置,实现对用户的权限控制
ServerAuthModule这里不细说,可以自行百度. 重点在注释: <!-- 声明用于安全约束的角色 --> <security-role> <role-name& ...
- 【Objective-C 基础】4.分类和协议
1.分类 OC提供了一种与众不同的方式--Category,可以动态的为已经存在的类添加新的行为(方法) 这样可以保证类的原始设计规模较小,功能增加时再逐步扩展. 使用Category对类进行扩展时, ...
- iOS之RunLoop
RunLoop是iOS线程相关的比较重要的一个概念,无论是主线程还是子线程,都对应一个RunLoop,如果没有RunLoop,线程会马上被系统回收. 本文主要CFRunLoop的源码解析,并简单阐述一 ...
- Python基本语法--数据结构与运算符
# -*- coding: utf-8 -*- print "Hello, Python!"; print ("Hello, Python!"); #行和缩进 ...
- SSH小结
工作有一段时间了,经常用SSH登录远程机器,但对原理一直不是很了解,所以查阅了一些资料,写个小结. 一. SSH是什么? SSH的全称是Secure Shell, 是一种"用来在不安全的网络 ...
- [ios]quartz2d画板功功能实现核心代码
//触摸开始 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // 1,获取对 ...
- 每天一道Java题[4]
问题 怎么将字符串转换为int? 解答 此题看似简单,但经常出现在笔试等地方,由于大家习惯了用IDE,有什么还真未必能写出来.通常都是parseInt()方法进行转换,如下: Int n = Inte ...