手机应用从页面A跳转到页面B,再从页面B返回A时,怎么保证A还是停留在之前所在的位置

手机应用从页面A跳转到页面B,再从页面B返回A时,怎么保证A还是停留在之前所在的位置,是通过点击手机上的返回键,不是页面上的返回按钮,页面上的返回按钮通过js
可以设置返回到之前的位置。
请大神指点!

3个回答

我试过的有两种方法:
1.对A页面数据做本地缓存,从B页面返回时A页面加载缓存数据之后就会停留在之前的位置;
2.每次滑动时记录A页面的滑动位置,存到本地(sessionStorage.setItem('lastScrollHeight',_height))
从B页面返回时取出这个位置($(window).scrollTop(sessionStorage.getItem('lastScrollHeight')))

整个页面框架都可以用jquery.load方法 百度一下有教程

保存状态,有简单的和复杂的及自定义的

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
把A页面finish掉,进入B页面,然后会退到桌面,点击软件,进入的却是A页面不是B页面

![图片说明](https://img-ask.csdn.net/upload/201811/19/1542599043_907636.gif)

微信公众开发能跳转到其他应用的页面吗???

开发微信服务号的时候,能不能实现我点击某个自定义菜单的时候,会跳转到其他应用,比如说,安卓市场的主界面???

iOS提问:两个应用间跳转,怎么写跳回之前的应用的方法

各路大神,请教下,当购物APP调用支付宝或微信支付时,不管支付成功与失败,都可以回到购物APP跳转之前的页面,微信和支付宝是怎么处理回到购物APP的,这个跳回购物APP时,购物APP也没有出现启动页,感觉是直接切换的应用,我自己用OpenURL练习时,应用A跳应用B,(不管B启动没启动B都会出现启动页,为什么B在后台的时候还是会出现启动页呢),我要在应用B上加一个button来返回应用A,用的方法还是OpenURL,(这样跳回应用A,A还是会出现启动页,是不是要用OpenURL来返回A,是的话还要再做什么处理么?不是的话改用什么办法?)

微信内置浏览器,点击返回强制重新加载前一个页面的问题

需求应该挺常见的吧,从列表页A跳转到详情页B,点击返回的时候希望回到列表页A当初浏览的位置。 其他浏览器都没有问题,因为都是静态保持页面原有的状态,只有微信内置浏览器会在返回后重新加载A页面。但也看到很多公众号的微应用返回后并不会刷新,看了看页面源代码也没看出有什么特别的。 目前已知的解决方案: 1、跳转B页面前在sessionStorage中存放A页面的数据,以及滚动条位置,A页面初始化时判断sessionStorage中的值,有的话就不重新请求服务器,而是显示sessionStorage中的值,并且scrollTo到指定位置。 2、往history中插入#以使返回失效,将详情页B做成div弹层,使用自定义的返回按钮来隐藏详情页。 由于种种原因以上两种方案都不想采用,不知道各位有没有更通用更直接的方法,比如在页面头部添加什么信息通知浏览器别刷新之类。

关于安卓页面跳转的问题

做了两个页面与页面跳转按钮,二页面想使用ListActivity,但是继承了ListActivity类后闪退 继承Activity时运行正常,但不能看到List效果,请大神帮忙看下代码,感谢 DEBUG 线程 [main](已暂挂(异常 RuntimeException)) ActivityThread.performLaunchActivity(ActivityThread$ActivityClientRecord, Intent) 行: 3254 ActivityThread.handleLaunchActivity(ActivityThread$ActivityClientRecord, Intent) 行: 3350 ActivityThread.access$1100(ActivityThread, ActivityThread$ActivityClientRecord, Intent) 行: 223 ActivityThread$H.handleMessage(Message) 行: 1794 ActivityThread$H(Handler).dispatchMessage(Message) 行: 102 Looper.loop() 行: 148 ActivityThread.main(String[]) 行: 7224 Method.invoke(Object, Object...) 行: 不可用 [本机方法] ZygoteInit$MethodAndArgsCaller.run() 行: 1230 ZygoteInit.main(String[]) 行: 1120 报错日志 04-11 10:03:01.957: E/MotionRecognitionManager(30956): mSContextService = android.hardware.scontext.ISContextService$Stub$Proxy@b530bca 04-11 10:03:01.967: E/MotionRecognitionManager(30956): motionService = com.samsung.android.motion.IMotionRecognitionService$Stub$Proxy@82fc13b 04-11 10:03:01.967: E/MotionRecognitionManager(30956): motionService = com.samsung.android.motion.IMotionRecognitionService$Stub$Proxy@82fc13b 04-11 10:03:01.967: D/AndroidRuntime(30956): Shutting down VM 04-11 10:03:01.967: E/AndroidRuntime(30956): FATAL EXCEPTION: main 04-11 10:03:01.967: E/AndroidRuntime(30956): Process: com.example.audiorecord, PID: 30956 04-11 10:03:01.967: E/AndroidRuntime(30956): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.audiorecord/com.example.audiorecord.Activity02}: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list' 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3254) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread.access$1100(ActivityThread.java:223) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.os.Handler.dispatchMessage(Handler.java:102) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.os.Looper.loop(Looper.java:148) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread.main(ActivityThread.java:7224) 04-11 10:03:01.967: E/AndroidRuntime(30956): at java.lang.reflect.Method.invoke(Native Method) 04-11 10:03:01.967: E/AndroidRuntime(30956): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 04-11 10:03:01.967: E/AndroidRuntime(30956): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 04-11 10:03:01.967: E/AndroidRuntime(30956): Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list' 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ListActivity.onContentChanged(ListActivity.java:243) 04-11 10:03:01.967: E/AndroidRuntime(30956): at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:479) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.Activity.setContentView(Activity.java:2388) 04-11 10:03:01.967: E/AndroidRuntime(30956): at com.example.audiorecord.Activity02.onCreate(Activity02.java:38) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.Activity.performCreate(Activity.java:6877) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136) 04-11 10:03:01.967: E/AndroidRuntime(30956): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207) 04-11 10:03:01.967: E/AndroidRuntime(30956): ... 9 more Activity1: package com.example.audiorecord; import java.io.File; import java.io.IOException; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.content.Intent; public class RecordActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); super.onCreate(savedInstanceState); /* 设置显示main.xml布局*/ setContentView(R.layout.main); /* findViewById(R.id.button1)取得布局main.xml中的button1 */ Button button = (Button) findViewById(R.id.button1); /* 监听button的事件信息*/ button.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { /* 新建一个Intent对象*/ Intent intent = new Intent(); /* 指定intent要启动的类*/ intent.setClass(RecordActivity.this, Activity02.class); /* 启动一个新的Activity */ startActivity(intent); /* 关闭当前的Activity */ RecordActivity.this.finish(); } }); } } Activity2 package com.example.audiorecord; import java.io.File; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.app.ListActivity; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; public class Activity02 extends ListActivity{ //声明 private List<String> items = null;//存放名称 private List<String> paths = null;//存放路径 private String rootPath = "/"; private TextView tv; private Button Back; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* 设置显示main2布局*/ setContentView(R.layout.main2); /* findViewById(R.id.button2)取得布局main.xml中的button2 */ /* 监听button的事件信息*/ tv = (TextView) this.findViewById(R.id.TextView); this.getFileDir(rootPath);//获取rootPath目录下的文件. Back = (Button) findViewById(R.id.back); Back.setOnClickListener(new BackListener()); } class BackListener implements OnClickListener { public void onClick(View v) { Intent intent = new Intent(); /* 指定intent要启动的类*/ intent.setClass(Activity02.this, RecordActivity.class); /* 启动一个新的Activity */ startActivity(intent); /* 关闭当前的Activity */ Activity02.this.finish(); } } public void getFileDir(String filePath) { try{ this.tv.setText("当前路径:"+filePath);// 设置当前所在路径 items = new ArrayList<String>(); paths = new ArrayList<String>(); File f = new File(filePath); File[] files = f.listFiles();// 列出所有文件 // 如果不是根目录,则列出返回根目录和上一目录选项 if (!filePath.equals(rootPath)) { items.add("返回根目录"); paths.add(rootPath); items.add("返回上一层目录"); paths.add(f.getParent()); } // 将所有文件存入list中 if(files != null){ int count = files.length;// 文件个数 for (int i = 0; i < count; i++) { File file = files[i]; items.add(file.getName()); paths.add(file.getPath()); } } ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items); this.setListAdapter(adapter); }catch(Exception ex){ ex.printStackTrace(); } } @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); String path = paths.get(position); File file = new File(path); //如果是文件夹就继续分解 if(file.isDirectory()){ this.getFileDir(path); }else{ new AlertDialog.Builder(this).setTitle("提示").setMessage(file.getName()+" 是一个文件!").setPositiveButton("OK", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which) { } }).show(); } }} MANIFEST <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.audiorecord" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".RecordActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Activity02"></activity> </application> </manifest>

jquery ajax方法调用在session超时以后如何跳转到登录页面?

jquery ajax方法调用在session超时以后如何跳转到登录页面? session超时以后虽然被过滤器过滤到了,但是并不会跳转到登录页面请求具体的解决方法。 我参考了这篇文章,但是我调用ajaxStart不起作用。 http://www.blogjava.net/vickzhu/archive/2009/06/05/280223.html ext jquery 用户访问超时(ext session过期) 解决两种情况下的用户访问超时。 a)普通http请求的session超时。 b)异步http请求的session超时,使用ext后大部分的界面刷新都是异步的ajax请求。 不管是那种类型的http请求总是可以由一个过滤器来捕捉。 分类:普通http请求的header参数中没有x-requested-with:XMLHttpRequest头信息,而异步的有。 其实对于常见的ajax框架,header中还有标示自己身份的header信息。 对于普通的http请求,发现session超时后直接重定向到一个超时页面,显示访问超时。 对于异步http请求,发现session超时后则向请求的response中写入特定的超时头信息,客户端ajax对象检测 头信息,发现有超时状态标志后调用显示超时信息的javascript方法,提示用户访问超时。 服务器端session超时后在过滤器中为response添加新的头信息,标记该请求超时: if(r.getHeader("x-requested-with")!=null && r.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){ response.setHeader("sessionstatus","timeout"); } 使用Ext.Ajaxt对象完成异步请求的交互,Ext.Ajax是单实例对象(非常重要,全局单一Ext.Ajax实例!)。 注册Ext.Ajax的requestcomplete事件,每个ajax请求成功后首先响应该事件。在该事件的回调函数里面判断 访问请求是否超时。使用Ext.Ajax对象的好处是,只需要引入一个包含了几行超时处理代码的js文件,就可以 为当前应用增加超时处理功能,原有代码不需要做任何修改。 使用Ext.Ajaxt对象完成异步请求交互,假如checkUserSessionStatus是你的回调方法,每个页面引用: Ext.Ajax.on('requestcomplete',checkUserSessionStatus, this); function checkUserSessionStatus(conn,response,options){ //Ext重新封装了response对象 if(typeof response.getResponseHeader.sessionstatus != 'undefined'){ //发现请求超时,退出处理代码... } } 可以利用的几个特性:a)所有的ajax请求均带有x-requested-with:XMLHttpRequest头信息b)Ext.Ajax是单实例对象(非常重要,全局单一Ext.Ajax实例!)c)注册Ext.Ajax的requestcomplete事件,每个ajax请求成功后首先响应该事件(概念类似spring的aop拦截)。 jquery提供了几个全局事件可以用来处理session过期请求,如当ajax请求开始时会触发ajaxStart()方法的回调函数;当ajax请求结束时,会触发ajaxStop()方法的回调函数。这些方法都是全局的方法,因此无论创建它们的代码位于何处,只要有ajax请求发生时,都会触发它们。类似的事件还有:ajaxComplete(),ajaxError(),ajaxSend(),ajaxSuccess()等。 如果使某个ajax请求不受全局方法的影响,那么可以在使用$.ajax()方法时,将参数中的global设置为false,jquery代码如下:$.ajax({ url:"test.html", global:false//不触发全局ajax事件}) 对于其他的ajax框架,解决用户访问请求超时这个问题的思路是类似的。

处理手机中返回键的问题

在我的应用程序中有4个activity: A (main activity) B C D 一般在程序中,在activity A中点击返回键时,程序会退出。在我这个例子中,如果activity 顺序是这样的A > B > C > A,那么如果我点击后退按钮,会去activity C,我想实现的是,就在这时程序就会退出。 假定,当主activity活动时,应用程序就会以某种方式删除历史活动。如何能够实现?

Android二级界面使用 startActivityForResult到三级界面,返回时直接回跳到一级界面

A到B到C的这样一个页面顺序。在B界面使用startActivityForResult跳到了C, 但是使用默认返回上一级(左上角的箭头和机身自带的返回按键)时,直接跳 回到A界面,B界面消失掉了但是通过intent和setResult的方法可以正确回到B界面,请问这是为什么,要怎么改,谢谢!

通过plus.webview.create方法打开第三方程序的页面后,如何通过点击第三方页面的按钮回到该页面?

刚接触H5,遇到一个问题,求教 (ಥ﹏ಥ) 在app中有一个页面A,通过plus.webview.create() 打开了一个第三方程序的页面 B。 现在想在第三方的页面 B中,放一个按钮,通过点击这个按钮,怎样能够回到 A页面。 B页面是一个普通的html页面。 跪求,不胜感激

JSP页面上输出12K(welogic上)后无法再跳转(高分悬赏!)

最近在项目中遇到这样一个奇怪的问题: 在页面上输入数据,点击submit按钮,程序跑到后台,然后什么都不做,直接返回到本画面。 画面上根据先前输入的数据生成自定义Tag。Tag会做一些业务判断,然后自动跳转到其他画面。 现在的问题是,在往其他画面跳的时候,老是报Cannot Forward a Response that is Already Committed 这个异常。 最后测试发现,几乎所有的服务器都有这个问题。就是在JSP页面上,当输出的字节数 超过8K(tomcate)/12K(weblogic)的时候,response.isCommitted()就变成了true,这个时侯就没法再 跳转了。 现在我想知道的是,这种限制是JSP页面特意的限制吗?谁能给一个正式的解释。 [b]问题补充:[/b] 谢谢各位的帮助,现在已经基本上知道深层的原因了。 主要是JSP页面在编译为HTML时,服务器不是直接往客户端浏览器写出,而是首先生成一个缓冲区。这个缓冲区的大小根据服务器的不同而不同,tomcate为8KB。当生成的HTML太大,超过缓冲区大小的时候,服务器就会向客户端写出,这个时候response的状态就会变为committed,就不能再往其他画面跳转了。因此,如果想实现在JSP页面上进行跳转,有两种途径: 1.在默认缓冲区写满之前跳转 2.修改缓冲区大小,使跳转动作发生在缓冲区写满之前 对于第二种途径,只要在进入JSP页面之后,立刻调用response.setBufferSize(int size)就可以了。保险起见,可将大小设为JSP编译后生成的HTML的大小。 TO:gembler 我们这个画面是一个测试工具画面,主要用来测试项目的自定义Tag。其中一个Tag有页面跳转逻辑,所以才会出这种问题。至于为什么跳转逻辑要放到Tag中,就不太清楚了。

页面跳转出错与session是否有关

我提交一个请求,后台处理后偶尔会跳到跟它完全不相干的一个页面中去,不知道为什么。 [b]问题补充:[/b] 不是 是我应用系统中的其他请求应该返回的页面

如何让 Activity 调用 finish() 之后不返回之前的 Activity?

在使用某个应用 A 的时候 Activity B 用 startActivity(new Intent(“B"));创建 Activity C,然后点击 Activity C 上的按钮 D,按钮 D 的处理函数中调用 finish();,然后返回了 Activity B。怎么才能在点击 Activity C 上的按钮 D 之后直接返回 应用 A?Activity B 和 Activity C 是在与应用 A 不同的另外一个应用里,就是我要写的应用。 找到解决方法了:https://stackoverflow.com/questions/20898083/android-how-to-return-to-previous-app-after-closing-notification-dialog

cas实现单点登录对filter能否设置是否显示登录页面?

项目描述: 现有服务A(论坛)和服务B(博客)及cas认证中心,对于服务A和B中相关文章是可以在未登录状态下进行浏览的,只是在留言或是发帖的时候才需进行登录 目前状况: 在具体客户服务端配置了casfilter,只对特定页面(比如说发帖、或是博客留言)配置了此filter。 存在问题: 比如说用户从在服务A通过cas认证中心登录了,此时链接到服务B,因为B服务中也是只只针对部分操作设置了casfitler,其结果就是当跳转到B服务的时候,并不能从cas认证中心获取到此用户信息,那么在服务B也无法设置本地服务的一些用户角色其权限信息 疑惑: 通过cas能否有比较好的方法,对于出现的这种情况,可以通过设置,比如说在访问到服务B的时候,仅仅到cas认证中心进行认证,看当前是否登录,如果登录的话,返回用户的登录信息;没有登录的话,直接返回用户原来所访问的页面,而不是目前的登录页面

第一次数据库查询成功,第二次查询去失败了?

我编写一个Android应用,A页面拥有一个选项菜单,点击菜单中的选项,跳转到B页面,B页面接收从A页面传递的数据后,进行数据库查询,在本页面中显示相关内容。 B页面中通过动态添加View的方法,添加了按钮,点击按钮,可进行数据库查询,获取相关值在页面显示。 不过我不想每次返回A页面,选择选项菜单的另一项再进入B页面,于是我在B页面同样放置了选项菜单,让我点击B页面上的选项菜单时,直接在B页面上显示,不过却出现“java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.Cursor android.database.sqlite.SQLiteDatabase.rawQuery(java.lang.String, java.lang.String[])' on a null object reference”的错误。 请问,要怎样做呢? 相关数据库查询的函数 public ArrayList<JapInfo> query_stylecolumn(String style_column, String alp_style) { String sql = String.format("SELECT hiragana,katakana,sound_path FROM Jap_Info AS j " + "LEFT JOIN Alp_style AS a " + "ON j.alpha_style_id = a.id " + "WHERE j.style_column = '%s' and a.style_name = '%s';",style_column,alp_style); ArrayList<JapInfo> japIf = new ArrayList<JapInfo>(); Cursor cursor = mDB.rawQuery(sql,null); while (cursor.moveToNext()){ JapInfo japIfo = new JapInfo(); japIfo.hiragana = cursor.getString(0); japIfo.katakana = cursor.getString(1); japIfo.sound_path = cursor.getString(2); japIf.add(japIfo); } cursor.close(); return japIf; }

Asp.net core identityServer4 回调跳转到signin-oidc得到404 Not Found的问题

我采用IdentityServer4[示例代码(Combined_AspId_and_EFStorage)](https://github.com/IdentityServer/IdentityServer4.Samples/tree/master/Quickstarts/Combined_AspId_and_EFStorage "") ,并参考了晓晨的博客([IdentityServer4(10)- 添加对外部认证的支持之QQ登录)](https://www.cnblogs.com/stulzq/p/7879101.html "")。 在第三方登录时开始都没问题,能够跳转到QQ授权页面并成功返回QQ用户信息,但是在跳转回MvcClient时却得到404空白页面: ## **404 Not Found** identity服务器的startup.cs代码如下: ``` public void ConfigureServices(IServiceCollection services) { Services = services; var connectionString = Configuration.GetConnectionString("qcloud-postgres-applicationdb"); var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(connectionString)); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_2); services.Configure<IISOptions>(iis => { iis.AuthenticationDisplayName = "Windows"; iis.AutomaticAuthentication = false; }); var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }) // this adds the config data from DB (clients, resources) .AddConfigurationStore(options => { options.ConfigureDbContext = b => b.UseNpgsql(Configuration.GetConnectionString("qcloud-postgres-configurationdb"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) // this adds the operational data from DB (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = b => b.UseNpgsql(Configuration.GetConnectionString("qcloud-postgres-persistedgrantdb"), sql => sql.MigrationsAssembly(migrationsAssembly)); // this enables automatic token cleanup. this is optional. options.EnableTokenCleanup = true; options.TokenCleanupInterval = 60; }) .AddAspNetIdentity<ApplicationUser>(); builder.AddDeveloperSigningCredential(); /* if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); }*/ services.AddAuthentication( options => { options.DefaultScheme = "QQ"; }) .AddQQ(qqOptions => { qqOptions.AppId = "AppId123456"; // qqOptions.AppKey = "AppKey1234567890"; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseIdentityServer(); app.UseMvcWithDefaultRoute(); } ``` MvcClient端的startup.cs代码如下: ``` public void ConfigureServices(IServiceCollection services) { Services = services; Services.AddMvc(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); Services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; //options.Authority = "http://localhost:5000"; options.Authority = "https://identity.web123456.cn"; options.RequireHttpsMetadata = false; options.ClientId = "yingyu88"; options.ClientSecret = "secret"; options.ResponseType = "code id_token"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("yingyu88api"); //options.Scope.Add("offline_access"); //options.ClaimActions.MapJsonKey("website", "website"); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseAuthentication(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } ``` 客户端得到的log如下: ``` 2019-03-23 11:36:07.588 +08:00 [INF] User profile not available. Using 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\4.0.30319.0\AutoGenKeys\S-1-5-82-1592072215-1740167268-757123690-3585059337-856257778\DataProtection' as key repository and Windows DPAPI to encrypt keys at rest. 2019-03-23 11:36:08.070 +08:00 [INF] Request starting HTTP/1.0 GET http://www.yingyu88.cn/Home/Secure 2019-03-23 11:36:08.187 +08:00 [INF] Route matched with {action = "Secure", controller = "Home"}. Executing action MvcClient.Controllers.HomeController.Secure (Yingyu88web) 2019-03-23 11:36:08.197 +08:00 [INF] Authorization failed. 2019-03-23 11:36:08.202 +08:00 [INF] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. 2019-03-23 11:36:08.209 +08:00 [INF] Executing ChallengeResult with authentication schemes ([]). 2019-03-23 11:36:08.713 +08:00 [INF] AuthenticationScheme: oidc was challenged. 2019-03-23 11:36:08.722 +08:00 [INF] Executed action MvcClient.Controllers.HomeController.Secure (Yingyu88web) in 531.87060000000008ms 2019-03-23 11:36:08.742 +08:00 [INF] Request finished in 673.8004ms 302 2019-03-23 11:36:15.048 +08:00 [INF] Request starting HTTP/1.0 POST http://www.yingyu88.cn/signin-oidc application/x-www-form-urlencoded 1532 2019-03-23 11:36:15.418 +08:00 [INF] AuthenticationScheme: Cookies signed in. 2019-03-23 11:36:15.419 +08:00 [INF] Request finished in 370.649ms 302 ``` 从以上Log可以看出Signin是成功的,但是callback回到signin-oidc之后请求就结束了,诡异的是应用并没有报错。 如有哪位大神熟悉IdentityServer的请多多赐教! 如果需要我这边更多的代码和log信息可以加QQ:352862120联系我私聊。多谢! 2019-03-29更新: ---- 经过试验发现,IdentityServer4的示例代码在调试状态下没有问题,能够在localhost:5000和localhost:5002之间跳转并传递相应的Cookies。但是部署到服务器后(我用的是windows 2016和iis)就不行了(代码完全一致)。最初直接想到的是跨域问题,但是加上AddCors也并没有解决。 ``` public void ConfigureServices(IServiceCollection services) { //配置跨域处理,允许所有来源: services.AddCors(options => options.AddPolicy("corspolicy", p => p.AllowAnyOrigin()) ); } public void Configure(IApplicationBuilder app) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseIdentityServer(); ** app.UseCors("corspolicy"); ** app.UseMvcWithDefaultRoute(); } ``` 以上代码加到了IdentityServer和MvcClient,但是并没有效果。 追踪部署环境和调试环境下的log可以发现,公网部署时IdentityServer运行到signin-oidc就停止了,没有任何报错。 这是公网部署时的log: ``` 2019-03-25 13:46:19.030 +08:00 [INF] Request starting HTTP/1.0 GET http://www.yingyu88.cn/Home/Secure 2019-03-25 13:46:19.031 +08:00 [INF] Route matched with {action = "Secure", controller = "Home"}. Executing action MvcClient.Controllers.HomeController.Secure (MvcClient) 2019-03-25 13:46:19.039 +08:00 [INF] Authorization failed. 2019-03-25 13:46:19.041 +08:00 [INF] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. 2019-03-25 13:46:19.045 +08:00 [INF] Executing ChallengeResult with authentication schemes ([]). 2019-03-25 13:46:19.403 +08:00 [INF] AuthenticationScheme: oidc was challenged. 2019-03-25 13:46:19.408 +08:00 [INF] Executed action MvcClient.Controllers.HomeController.Secure (MvcClient) in 376.51370000000003ms 2019-03-25 13:46:19.413 +08:00 [INF] Request finished in 382.7936ms 302 2019-03-25 13:46:40.244 +08:00 [INF] Request starting HTTP/1.0 POST http://www.yingyu88.cn/signin-oidc application/x-www-form-urlencoded 1531 2019-03-25 13:46:40.651 +08:00 [INF] AuthenticationScheme: Cookies signed in. 2019-03-25 13:46:40.651 +08:00 [INF] Request finished in 406.993ms 302 ``` 这是调试环境下的log: ``` 2019-03-25 12:32:15.062 +08:00 [INF] Request starting HTTP/1.1 GET http://localhost:5002/Home/Secure 2019-03-25 12:32:15.064 +08:00 [INF] Route matched with {action = "Secure", controller = "Home"}. Executing action MvcClient.Controllers.HomeController.Secure (MvcClient) 2019-03-25 12:32:15.070 +08:00 [INF] Authorization failed. 2019-03-25 12:32:15.072 +08:00 [INF] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. 2019-03-25 12:32:15.073 +08:00 [INF] Executing ChallengeResult with authentication schemes ([]). 2019-03-25 12:32:15.077 +08:00 [INF] AuthenticationScheme: oidc was challenged. 2019-03-25 12:32:15.077 +08:00 [INF] Executed action MvcClient.Controllers.HomeController.Secure (MvcClient) in 13.078700000000001ms 2019-03-25 12:32:15.077 +08:00 [INF] Request finished in 14.6766ms 302 2019-03-25 12:32:39.168 +08:00 [INF] Request starting HTTP/1.1 POST http://localhost:5002/signin-oidc application/x-www-form-urlencoded 1522 2019-03-25 12:32:39.543 +08:00 [INF] AuthenticationScheme: Cookies signed in. 2019-03-25 12:32:39.543 +08:00 [INF] Request finished in 375.4138ms 302 //以下是调试环境下继续执行跳转回/home/secure的动作。部署后这些动作就没有被执行。 2019-03-25 12:32:39.550 +08:00 [INF] Request starting HTTP/1.1 GET http://localhost:5002/Home/Secure 2019-03-25 12:32:39.551 +08:00 [INF] Route matched with {action = "Secure", controller = "Home"}. Executing action MvcClient.Controllers.HomeController.Secure (MvcClient) 2019-03-25 12:32:39.551 +08:00 [INF] Authorization was successful. 2019-03-25 12:32:39.551 +08:00 [INF] Executing action method MvcClient.Controllers.HomeController.Secure (MvcClient) - Validation state: "Valid" 2019-03-25 12:32:39.552 +08:00 [INF] Executed action method MvcClient.Controllers.HomeController.Secure (MvcClient), returned result Microsoft.AspNetCore.Mvc.ViewResult in 0.2637ms. 2019-03-25 12:32:39.556 +08:00 [INF] Executing ViewResult, running view Secure. 2019-03-25 12:32:39.562 +08:00 [INF] Executed ViewResult - view Secure executed in 10.0428ms. 2019-03-25 12:32:39.563 +08:00 [INF] Executed action MvcClient.Controllers.HomeController.Secure (MvcClient) in 11.7323ms 2019-03-25 12:32:39.565 +08:00 [INF] Request finished in 14.3843ms 200 text/html; charset=utf-8 ``` 观察对比两种环境下的cookie,发现部署后从IdentityServer跳转到MvcClient/signin-oidc后少了两个cookie: .AspNetCore.Identity.Application idsrv.session ---- 从IdentityServer4官方的示例代码来看,其示例代码可能还无法直接应用于部署环境,在startup.cs中有一段代码: ``` if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); } ``` 由此可见sigin-oidc的404问题有可能是解密凭据引起的。但是我对ASP.net core源码了解太少,提供上述信息希望能够得到大神的指点。 2019-03-29更新:AddDeveloperSigningCredential会生成RSA加密证书,使得程序能够正常运行,虽然其安全性会比较差。详见[IdentityServer4部署到服务器,配置证书问题](https://www.jianshu.com/p/1b82f6d2644e "")。因此AddDeveloperSigningCredential并非导致本次问题的原因。 ---- 2019-03-26更新: 如果把IdentityServer4.Samples\Quickstarts\4_ImplicitFlowAuthenticationWithExternal示例部署到同样的环境,发现能够运行通过。但是如果改为Hybrid模式就会出现signin-oidc 404 Not Found的问题。 identityserver.config.cs代码: ``` // OpenID Connect hybrid flow client (MVC) new Client { ClientId = "mvc", ClientName = "MVC Client", // 能正常部署运行: AllowedGrantTypes = GrantTypes.Implicit, // 会出现404问题: AllowedGrantTypes = GrantTypes.Hybrid, ClientSecrets = { new Secret("secret".Sha256()) }, RedirectUris = { "http://www.someweb.cn/signin-oidc" }, PostLogoutRedirectUris = { "http://www.someweb.cn/signout-callback-oidc" }, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api1" }, AllowOfflineAccess = true } ``` MvcClient.startup.cs: ``` { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "https://identity.someweb.cn"; options.RequireHttpsMetadata = false; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("offline_access"); options.ClaimActions.MapJsonKey("website", "website"); // 能够正常部署运行: options.ResponseType = "id_token"; // 会发生signin-oidc 404错误: options.Scope.Add("api1"); options.ResponseType = "code id_token"; // 会发生"invalid_scope" 错误: options.Scope.Add("api1"); options.ResponseType = "id_token"; }); ``` 现在虽然已经知道Hybrid模式下公网部署才会出现错误,但究竟是我对client的配置错误还是IS4的bug所引起的问题并不清楚。 我试过AddCors,但并没有解决以上问题。

spring mvc+shiro+cas 实现cas client功能 跳转回来404

http://securitycenter.com:8080/gtsys/cas?ticket=ST-14-HEDhc1GVQt0UYdiZpi7R-cas 返回这个地址 404 ![图片说明](https://img-ask.csdn.net/upload/201510/09/1444404164_27274.png) ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd" > <!-- 定时器开关 开始 --> <task:annotation-driven /> <!-- 标注类型 的事务配置 如果使用注解事务。就放开 <tx:annotation-driven />--> <!-- 统一异常处理方式 --> <bean id="exceptionHandler" class="com.lanyuan.exception.MyExceptionHandler"/> <!-- 初始化数据 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" > <property name ="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> <property name="ignoreUnresolvablePlaceholders" value="true" /> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driverClass}" /> </bean> <bean id="pagePlugin" class="com.lanyuan.plugin.PagePlugin"> <property name="properties"> <props> <prop key="dialect">mysql</prop> <prop key="pageSqlId">.*query.*</prop> </props> </property> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动匹配Mapper映射文件 --> <property name="mapperLocations" value="classpath:mappings/*-mapper.xml"/> <property name="typeAliasesPackage" value="com.lanyuan.entity"/> <property name="plugins"> <array> <ref bean="pagePlugin" /> </array> </property> </bean> <!-- 通过扫描的模式,扫描目录在com.lanyuan.mapper目录下,所有的mapper都继承SqlMapper接口的接口, 这样一个bean就可以了 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.lanyuan.mapper" /> </bean> <!-- 事务配置 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- <aop:config> <aop:pointcut expression="execution(public * com.lanyuan.controller.*(..))" id="pointcut" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="query*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="logicDelById" propagation="REQUIRED" /> </tx:attributes> </tx:advice> --> <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="log4jHandlerAOP" class="com.lanyuan.logAop.LogAopAction"></bean> <aop:config proxy-target-class="true"> <aop:aspect id="logAspect" ref="log4jHandlerAOP"> <aop:pointcut id="logPointCut" expression="execution(* org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(..))" /> <aop:around method="logAll" pointcut-ref="logPointCut" /> </aop:aspect> </aop:config> --> <!-- 使用Spring组件扫描的方式来实现自动注入bean --> <context:component-scan base-package="com.lanyuan.task" /> <!-- 隐式地向 Spring 容器注册 --> <context:annotation-config /> </beans> spring-application.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd" > <tx:annotation-driven /> <context:component-scan base-package="com.lanyuan.controller" /> <context:component-scan base-package="com.lanyuan.logAop" /> <!-- 启动对@AspectJ注解的支持 --> <!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller--> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 注解支持 --> <context:annotation-config/> <!--避免IE执行AJAX时,返回JSON出现下载文件 --> <bean id="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>text/json;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> <!-- 采用SpringMVC自带的JSON转换工具,支持@ResponseBody注解 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJackson2HttpMessageConverter" /> <!-- JSON转换器 --> </list> </property> </bean> <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean> <mvc:annotation-driven> <!-- 处理responseBody 里面日期类型 --> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 默认编码 --> <property name="defaultEncoding" value="utf-8" /> <!-- 文件大小最大值 --> <property name="maxUploadSize" value="10485760000" /> <!-- 内存中的最大值 --> <property name="maxInMemorySize" value="40960" /> </bean> <import resource="spring-mvc-shiro.xml"/> </beans> spring-mvc.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" > <property name ="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> <property name="ignoreUnresolvablePlaceholders" value="true" /> </bean> <bean id="credentialsMatcher" class="com.lanyuan.shiro.credentials.RetryLimitHashedCredentialsMatcher"> <!-- hashAlgorithmName必须的,没有默认值。可以有MD5或者SHA-1,如果对密码安全有更高要求可以用SHA-256或者更高。 这里使用MD5 storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 hashIterations迭代次数,默认值是1。 --> <constructor-arg ref="cacheManager" /> <property name="hashAlgorithmName" value="md5" /> <!--<property name="hashIterations" value="2" />--> <!--<property name="storedCredentialsHexEncoded" value="true" />--> </bean> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <!-- sid如果改为JSESSIONID会导致重定向循环 --> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="-1"/> </bean> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="2592000"/><!-- 30天 --> </bean> <!-- rememberMe管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)--> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/> <!-- 凭证匹配器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="casRealm" /> <property name="sessionManager" ref="sessionManager"/> <!-- 使用下面配置的缓存管理器 --> <property name="cacheManager" ref="cacheManager" /> <property name="rememberMeManager" ref="rememberMeManager"/> <property name="subjectFactory" ref="casSubjectFactory"/> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!--自定义Realm --> <!-- <bean id="myRealm" class="com.lanyuan.shiro.MyRealm"> <property name="credentialsMatcher" ref="credentialsMatcher" /> <property name="cachingEnabled" value="false" /> --> <!-- 如需要自定义缓存时间放开以下.修改 ehcache.xml--> <!--<property name="authenticationCachingEnabled" value="true"/>--> <!--<property name="authenticationCacheName" value="authenticationCache"/>--> <!--<property name="authorizationCachingEnabled" value="true"/>--> <!--<property name="authorizationCacheName" value="authorizationCache"/>--> <!-- </bean> --> <!-- <property name="userService" ref="userService"/> --> <bean id="casRealm" class="com.lanyuan.shiro.MyCasRealm"> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> <!--该地址为cas server地址 --> <property name="casServerUrlPrefix" value="${shiro.casServer.url}"/> <!-- 该地址为是当前应用 CAS 服务 URL,即用于接收并处理登录成功后的 Ticket 的, 必须和loginUrl中的service参数保持一致,否则服务器会判断service不匹配--> <property name="casService" value="${shiro.client.cas}"/> </bean> <bean id="sysUserFilter" class="com.lanyuan.shiro.filter.SysUserFilter"/> <bean id="kickoutSessionControlFilter" class="com.lanyuan.shiro.filter.KickoutSessionControlFilter"> <property name="cacheManager" ref="cacheManager"/> <property name="sessionManager" ref="sessionManager"/> <property name="kickoutAfter" value="false"/> <property name="maxSession" value="1"/> <property name="kickoutUrl" value="/login.shtml"/> </bean> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <!--配置验证错误时的失败页面(Ticket 校验不通过时展示的错误页面) --> <property name="failureUrl" value="${shiro.failureUrl}"/> </bean> <bean id="casLogoutFilter" class="io.github.howiefh.cas.session.CasLogoutFilter"> <property name="sessionManager" ref="sessionManager"/> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="${shiro.logout.url}"/> </bean> <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- <property name="loginUrl" value="/login.shtml" /> <property name="successUrl" value="/index.shtml" /> --> <property name="loginUrl" value="${shiro.login.url}"/> <property name="successUrl" value="${shiro.login.success.url}"/> <property name="unauthorizedUrl" value="/denied.jsp" /> <!-- 自定义权限配置 --> <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" /> <property name="filters"> <util:map> <entry key="cas" value-ref="casFilter"/> <entry key="logout" value-ref="logoutFilter" /> <entry key="casLogout" value-ref="casLogoutFilter" /> <entry key="sysUser" value-ref="sysUserFilter"/> <entry key="kickout" value-ref="kickoutSessionControlFilter"/> </util:map> </property> </bean> <!--自定义filterChainDefinitionMap --> <bean id="chainDefinitionSectionMetaSource" class="com.lanyuan.shiro.ChainDefinitionSectionMetaSource"> <property name="filterChainDefinitions"> <value> /casFailure.jsp = anon /cas = casLogout,cas /logout = logout /favicon.ico = anon /admin_files/** = anon /fonts/** = anon /404/** = anon /error.jsp = anon /js/** = anon /layer-v1.9.2/** = anon /notebook/** = anon /login.shtml = anon /denied.jsp = anon /install.shtml = anon /lanyuan.shtml = anon /** = casLogout,user </value> </property> </bean> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 会话DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 会话验证调度器 --> <!-- 全局的会话信息检测扫描信息间隔30分钟--> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- 会话管理器 --> <!-- 全局的会话信息设置成30分钟,sessionValidationSchedulerEnabled参数就是是否开启扫描 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!--shiro缓存管理器 --> <bean id="cacheManager" class="com.lanyuan.shiro.spring.SpringCacheManagerWrapper" > <property name="cacheManager" ref="springCacheManager"/> </bean> <bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcacheManager"/> </bean> <!--ehcache--> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans> spring-shiro.xml <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <display-name>gtsys</display-name> <!-- 单点登出 --> <!-- <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <filter> <filter-name>CAS Single Sign Out Filter</filter-name> <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> </filter> <filter-mapping> <filter-name>CAS Single Sign Out Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-shiro.xml,classpath:spring-application.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.shtml</url-pattern> </servlet-mapping> <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.eot</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.ttf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.xml</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.swf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.zip</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.woff</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>login.shtml</welcome-file> </welcome-file-list> </web-app> web.xml ## shiro shiro.session.timeout=1800000 shiro.session.validate.timespan=1800000 # cas\u767B\u5F55URL shiro.login.url=https://localhost:8443/cas-server/login?service=http://securitycenter.com:8080/gtsys/cas # cas logout shiro.logout.url=https://localhost:8443/cas-server/logout?service=http://securitycenter.com:8080/gtsys # cas\u767B\u5F55\u6210\u529F\u8DF3\u8F6CURL shiro.login.success.url=http://securitycenter.com:8080/gtsys/index.shtml # cas\u670D\u52A1\u5668URL shiro.casServer.url=https://localhost:8443/cas-server # \u5BA2\u6237\u7AEFCAS\u767B\u5F55URL shiro.client.cas=http://securitycenter.com:8080/gtsys/cas # \u5BA2\u6237\u7AEFCAS\u9A8C\u8BC1\u5931\u8D25\u8DF3\u8F6CURL shiro.failureUrl=/casFailure.jsp ## dataSource dataSource.driver=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 dataSource.username=root dataSource.password=1234 properties文件 <?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir"/> <!-- <diskStore>==========当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口) * <diskStore path="">==用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是*.data和*.index * name=================缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里) * maxElementsOnDisk====磁盘缓存中最多可以存放的元素数量,0表示无穷大 * maxElementsInMemory==内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况 * 1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中 * 2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素 * eternal==============缓存中对象是否永久有效,即是否永驻内存,true时将忽略timeToIdleSeconds和timeToLiveSeconds * timeToIdleSeconds====缓存数据在失效前的允许闲置时间(单位:秒),仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,此为可选属性 * 即访问这个cache中元素的最大间隔时间,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除 * timeToLiveSeconds====缓存数据在失效前的允许存活时间(单位:秒),仅当eternal=false时使用,默认值是0表示可存活时间无穷大 * 即Cache中的某元素从创建到清楚的生存时间,也就是说从创建开始计时,当超过这个时间时,此元素将从Cache中清除 * overflowToDisk=======内存不足时,是否启用磁盘缓存(即内存中对象数量达到maxElementsInMemory时,Ehcache会将对象写到磁盘中) * 会根据标签中path值查找对应的属性值,写入磁盘的文件会放在path文件夹下,文件的名称是cache的名称,后缀名是data * diskPersistent=======是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件 * 这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存 * 要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法 * diskExpiryThreadIntervalSeconds==磁盘缓存的清理线程运行间隔,默认是120秒 * diskSpoolBufferSizeMB============设置DiskStore(磁盘缓存)的缓存区大小,默认是30MB * memoryStoreEvictionPolicy========内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存 * 共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出) --> <!-- 注意,以下缓存是永久有效,是系统初始化数据到缓存中,如果不需要永久有效,请另写,或在 --> <cache name="cache" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> </cache> <!-- 登录记录缓存 锁定10分钟 --> <cache name="passwordRetryCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <!-- <cache name="authorizationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="authenticationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> --> <cache name="shiro-activeSessionCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="shiro-kickout-session" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> </ehcache> ehcache.xml package com.lanyuan.shiro; //import com.github.zhangkaitao.shiro.chapter15.service.UserService; import java.util.List; import javax.inject.Inject; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cas.CasRealm; import org.apache.shiro.subject.PrincipalCollection; import com.lanyuan.entity.ResFormMap; import com.lanyuan.mapper.ResourcesMapper; import com.lanyuan.mapper.UserMapper; /** * <p>User: Zhang Kaitao * <p>Date: 14-2-13 * <p>Version: 1.0 */ public class MyCasRealm extends CasRealm { // private UserService userService; // // public void setUserService(UserService userService) { // this.userService = userService; // } @Inject private ResourcesMapper resourcesMapper; @Inject private UserMapper userMapper; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); // PathMatchingFilterChainResolver SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //authorizationInfo.setRoles(userService.findRoles(username)); // authorizationInfo.setStringPermissions(userService.findPermissions(username)); String userId = SecurityUtils.getSubject().getSession().getAttribute("userSessionId").toString(); List<ResFormMap> rs = resourcesMapper.findUserResourcess(userId); for (ResFormMap resources : rs) { authorizationInfo.addStringPermission(resources.get("resKey").toString()); } return authorizationInfo; } } MyCasRealm.java ``` ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:config proxy-target-class="true"></aop:config> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans> spring-mvc-shiro.xml ``` 这个是更改 网上的蓝缘系统的 cas server 和cas client参考的 http://howiefh.github.io/2015/05/19/shiro-cas-single-sign-on/?utm_source=tuicool 不知道为什么会返回404

求指导,谢谢各位大神。 ViewPager和FragmentPagerAdapter实现切换,但是无法显示数据

**想做个应用市场,效果如图,下面的是一级标签,用的TabHost跳转Activity实现。然后上面这一排是二级标签,想用TextView + ViewPager + Fragment 实现,现在滑动有效,但是数据加载不出来。求指教,捉急一整天了。 ![CSDN移动问答][1] ![CSDN移动问答][2] 这是“推荐”对应的Activity:** public class CommendActivity extends FragmentActivity { private static final int INDEX_COM = 0; private static final int INDEX_NEW = 1; private static final int INDEX_HOT = 2; private static final int INDEX_GUESS = 3; private ImageView comPointer; // 指针 private TextView comCom, comNew, comHot, comGuess; // 标签 private ViewPager comPager; private PagerAdapter pagerAdapter; private List<CommendFragment> fragments; private int currentPage = 0; // 当前二级页 private int delta = 0; // 指针单位移动量 private int offset = 0; // 指针移动偏移值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_commend); initPointer(); initTextView(); initViewPager(); } /* * 配置标签 */ private void initTextView() { comCom = (TextView) findViewById(R.id.comCom); comNew = (TextView) findViewById(R.id.comNew); comHot = (TextView) findViewById(R.id.comHot); comGuess = (TextView) findViewById(R.id.comGuess); comClickListener listener = new comClickListener(); comCom.setOnClickListener(listener); comNew.setOnClickListener(listener); comHot.setOnClickListener(listener); comGuess.setOnClickListener(listener); } /* * 配置标签指针 */ private void initPointer() { comPointer = (ImageView) findViewById(R.id.comPointer); int imageWidth = BitmapFactory.decodeResource(getResources(), R.drawable.pointer).getWidth(); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); delta = dm.widthPixels / 4; offset = (delta - imageWidth) / 2; Matrix matrix = new Matrix(); matrix.postTranslate(offset, 0); comPointer.setImageMatrix(matrix); } /* * 配置ViewPager */ private void initViewPager() { comPager = (ViewPager) findViewById(R.id.comPager); fragments = new ArrayList<CommendFragment>(); CommendFragment comFragment = CommendFragment.newInstance(INDEX_COM); CommendFragment newFragment = CommendFragment.newInstance(INDEX_NEW); CommendFragment hotFragment = CommendFragment.newInstance(INDEX_HOT); CommendFragment guessFragment = CommendFragment.newInstance(INDEX_GUESS); fragments.add(comFragment); fragments.add(newFragment); fragments.add(hotFragment); fragments.add(guessFragment); comPager.setAdapter(new TabsAdapter(getSupportFragmentManager(), fragments)); comPager.setCurrentItem(currentPage); comPager.setOnPageChangeListener(new ComPageChangeListener()); } private class comClickListener implements OnClickListener { @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.comCom: comPager.setCurrentItem(INDEX_COM); break; case R.id.comNew: comPager.setCurrentItem(INDEX_NEW); break; case R.id.comHot: comPager.setCurrentItem(INDEX_HOT); break; case R.id.comGuess: comPager.setCurrentItem(INDEX_GUESS); break; } } } private class ComPageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int state) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { Toast.makeText( CommendActivity.this, "this is " + ((TabsAdapter)comPager.getAdapter()).getItem(position), Toast.LENGTH_SHORT) .show(); Animation anim = new TranslateAnimation(delta * currentPage, delta * position, 0, 0); currentPage = position; anim.setFillAfter(true); anim.setDuration(300); comPointer.startAnimation(anim); } } } **Adapter的java代码:** public class TabsAdapter extends FragmentPagerAdapter { private List<CommendFragment> fragments; public TabsAdapter(FragmentManager fm, List<CommendFragment> list) { super(fm); this.fragments = list; } @Override public int getCount() { return fragments.size(); } @Override public boolean isViewFromObject(View view, Object obj) { return view == obj; } @Override public Fragment getItem(int position) { return fragments.get(position); } } **Fragment的java代码:** public class CommendFragment extends Fragment { private static final int DEFAULT_TAG = -1; private int tag; private TextView tv; /** * 添加标识,返回带标识的对象。 * * @param tag * 标识 * @return 带标识的Fragment */ public static CommendFragment newInstance(int tag) { CommendFragment fragment = new CommendFragment(); Bundle b = new Bundle(); b.putInt("tag", tag); fragment.setArguments(b); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle b = getArguments(); tag = (null == b ? DEFAULT_TAG : b.getInt("tag")); } /** * 解析布局 */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_com, container, false); tv = (TextView) view.findViewById(R.id.empty); tv.setText(tv.getText().toString() + tag); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } } [1]: http://img1.ph.126.net/fxzDnnu6ODkwAVCuK-bChw==/6597399620146971619.jpg [2]: http://img1.ph.126.net/0I9zg-8JmaTJ7aOhFH3cvw==/1929792440428526119.jpg

一年半之前的疑问,再问一遍,基础的

缘起:07年8月进公司发现公司的控制页面跳转和功能执行方式如下, jsp页面存放两个隐藏参数: 1)view:决定处理类型; 2)action:决定处理方式: 3)服务器端controller代码结构: [code="java"] if(view.equals("insert")){ if("insertProjectMes".equals(action)){ } if("insertPictures".equals(action)){ } ... } else if(view.equals("update")){ ... } else if(view.equals("select")){ ... } else if(view.equals("delete")){ ... } [/code] 每个controller十几个if,else也是家常便饭,多的时候几十个,而且业务经常新增,看到03年一直被修改过来的代码也是经常的事。 辞职在家进修学习,又想这个问题:请问怎么去除这些if else呢? 个人想法(spring): 1)在spring上下文中配置一个jsp,和controller,和一个action参数 2)在jsp中放置参数<input type="hidden" name="action" value="">,值在第一次访问jsp的时候被spring注入; 3)controller中 a)定义四个接口,对应操作类型:有参数无返回,无参数无返回,有参数有返回,有参数无返回; public interface Do1 { Object doing();//无参数有返回 } public interface Do2 { void doing();//无返回无参数 } public interface Do3 { void doing(Object o);//无返回有参数 } public interface Do4 { Object doing(Object o);//有返回有参数 } b)业务处理类,以action的值命名,实现上面某个接口,controller的内部类实现并存入map对象 c)controller通过map对象管理处理类,并在客户提交的时候根据传过来的action参数反射调用相应的业务处理类。 似乎就是一个状态模式。好处就是每个人需要添加的时候只要在后面添加新的内部类,并把自己加入map就行。 请问怎么去除这些if else呢? 谢谢

android关于点击按钮事件的处理

首先先谢谢回答的问题的好人们,好人有好报~ 我是一个纯android新手,很纯很纯的那种,最近要交一个作业,我就想写一个时间追踪的安卓应用,因为比较出名的那几个有的付费有的用不来。 现在卡在了关于用户自己添加一个任务的问题上,附图如下:![CSDN移动问答][1] [1]: http://ntu.me/di/T6OWV/QQ%E5%9B%BE%E7%89%8720140519123655.jpg 根据我的理解,上面的学习编程啦、读书啦应该是按钮,点击就会开始自动计时,而这些都是点新增项目自己添加的 我就想知道那个新增项目要如何实现? 自己也研究了一天,现在觉得点新增肯定是跳到另一个界面,然后输入任务名称,再带着数据返回,可是怎样才能在这个页面添加一个新按钮?又实现一点它就计时的方法?最后我自己还是没找到答案 所以向各位大神求解,谢谢谢谢~

在中国程序员是青春饭吗?

今年,我也32了 ,为了不给大家误导,咨询了猎头、圈内好友,以及年过35岁的几位老程序员……舍了老脸去揭人家伤疤……希望能给大家以帮助,记得帮我点赞哦。 目录: 你以为的人生 一次又一次的伤害 猎头界的真相 如何应对互联网行业的「中年危机」 一、你以为的人生 刚入行时,拿着傲人的工资,想着好好干,以为我们的人生是这样的: 等真到了那一天,你会发现,你的人生很可能是这样的: ...

程序员请照顾好自己,周末病魔差点一套带走我。

程序员在一个周末的时间,得了重病,差点当场去世,还好及时挽救回来了。

Java基础知识面试题(2020最新版)

文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类有何不同?Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的对比基础语法数据类型Java有哪些数据类型switc...

和黑客斗争的 6 天!

互联网公司工作,很难避免不和黑客们打交道,我呆过的两家互联网公司,几乎每月每天每分钟都有黑客在公司网站上扫描。有的是寻找 Sql 注入的缺口,有的是寻找线上服务器可能存在的漏洞,大部分都...

Intellij IDEA 实用插件安利

1. 前言从2020 年 JVM 生态报告解读 可以看出Intellij IDEA 目前已经稳坐 Java IDE 头把交椅。而且统计得出付费用户已经超过了八成(国外统计)。IDEA 的...

搜狗输入法也在挑战国人的智商!

故事总是一个接着一个到来...上周写完《鲁大师已经彻底沦为一款垃圾流氓软件!》这篇文章之后,鲁大师的市场工作人员就找到了我,希望把这篇文章删除掉。经过一番沟通我先把这篇文章从公号中删除了...

总结了 150 余个神奇网站,你不来瞅瞅吗?

原博客再更新,可能就没了,之后将持续更新本篇博客。

副业收入是我做程序媛的3倍,工作外的B面人生是怎样的?

提到“程序员”,多数人脑海里首先想到的大约是:为人木讷、薪水超高、工作枯燥…… 然而,当离开工作岗位,撕去层层标签,脱下“程序员”这身外套,有的人生动又有趣,马上展现出了完全不同的A/B面人生! 不论是简单的爱好,还是正经的副业,他们都干得同样出色。偶尔,还能和程序员的特质结合,产生奇妙的“化学反应”。 @Charlotte:平日素颜示人,周末美妆博主 大家都以为程序媛也个个不修边幅,但我们也许...

MySQL数据库面试题(2020最新版)

文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储引擎MyISAM与InnoDB区别MyISAM索引与InnoDB索引的区别?InnoDB引擎的4大特性存储引擎选择索引什么是索引?索引有哪些优缺点?索引使用场景(重点)...

如果你是老板,你会不会踢了这样的员工?

有个好朋友ZS,是技术总监,昨天问我:“有一个老下属,跟了我很多年,做事勤勤恳恳,主动性也很好。但随着公司的发展,他的进步速度,跟不上团队的步伐了,有点...

我入职阿里后,才知道原来简历这么写

私下里,有不少读者问我:“二哥,如何才能写出一份专业的技术简历呢?我总感觉自己写的简历太烂了,所以投了无数份,都石沉大海了。”说实话,我自己好多年没有写过简历了,但我认识的一个同行,他在阿里,给我说了一些他当年写简历的方法论,我感觉太牛逼了,实在是忍不住,就分享了出来,希望能够帮助到你。 01、简历的本质 作为简历的撰写者,你必须要搞清楚一点,简历的本质是什么,它就是为了来销售你的价值主张的。往深...

魂迁光刻,梦绕芯片,中芯国际终获ASML大型光刻机

据羊城晚报报道,近日中芯国际从荷兰进口的一台大型光刻机,顺利通过深圳出口加工区场站两道闸口进入厂区,中芯国际发表公告称该光刻机并非此前盛传的EUV光刻机,主要用于企业复工复产后的生产线扩容。 我们知道EUV主要用于7nm及以下制程的芯片制造,光刻机作为集成电路制造中最关键的设备,对芯片制作工艺有着决定性的影响,被誉为“超精密制造技术皇冠上的明珠”,根据之前中芯国际的公报,目...

优雅的替换if-else语句

场景 日常开发,if-else语句写的不少吧??当逻辑分支非常多的时候,if-else套了一层又一层,虽然业务功能倒是实现了,但是看起来是真的很不优雅,尤其是对于我这种有强迫症的程序"猿",看到这么多if-else,脑袋瓜子就嗡嗡的,总想着解锁新姿势:干掉过多的if-else!!!本文将介绍三板斧手段: 优先判断条件,条件不满足的,逻辑及时中断返回; 采用策略模式+工厂模式; 结合注解,锦...

离职半年了,老东家又发 offer,回不回?

有小伙伴问松哥这个问题,他在上海某公司,在离职了几个月后,前公司的领导联系到他,希望他能够返聘回去,他很纠结要不要回去? 俗话说好马不吃回头草,但是这个小伙伴既然感到纠结了,我觉得至少说明了两个问题:1.曾经的公司还不错;2.现在的日子也不是很如意。否则应该就不会纠结了。 老实说,松哥之前也有过类似的经历,今天就来和小伙伴们聊聊回头草到底吃不吃。 首先一个基本观点,就是离职了也没必要和老东家弄的苦...

2020阿里全球数学大赛:3万名高手、4道题、2天2夜未交卷

阿里巴巴全球数学竞赛( Alibaba Global Mathematics Competition)由马云发起,由中国科学技术协会、阿里巴巴基金会、阿里巴巴达摩院共同举办。大赛不设报名门槛,全世界爱好数学的人都可参与,不论是否出身数学专业、是否投身数学研究。 2020年阿里巴巴达摩院邀请北京大学、剑桥大学、浙江大学等高校的顶尖数学教师组建了出题组。中科院院士、美国艺术与科学院院士、北京国际数学...

为什么你不想学习?只想玩?人是如何一步一步废掉的

不知道是不是只有我这样子,还是你们也有过类似的经历。 上学的时候总有很多光辉历史,学年名列前茅,或者单科目大佬,但是虽然慢慢地长大了,你开始懈怠了,开始废掉了。。。 什么?你说不知道具体的情况是怎么样的? 我来告诉你: 你常常潜意识里或者心理觉得,自己真正的生活或者奋斗还没有开始。总是幻想着自己还拥有大把时间,还有无限的可能,自己还能逆风翻盘,只不是自己还没开始罢了,自己以后肯定会变得特别厉害...

百度工程师,获利10万,判刑3年!

所有一夜暴富的方法都写在刑法中,但总有人心存侥幸。这些年互联网犯罪高发,一些工程师高技术犯罪更是引发关注。这两天,一个百度运维工程师的案例传遍朋友圈。1...

程序员为什么千万不要瞎努力?

本文作者用对比非常鲜明的两个开发团队的故事,讲解了敏捷开发之道 —— 如果你的团队缺乏统一标准的环境,那么即使勤劳努力,不仅会极其耗时而且成果甚微,使用...

为什么程序员做外包会被瞧不起?

二哥,有个事想询问下您的意见,您觉得应届生值得去外包吗?公司虽然挺大的,中xx,但待遇感觉挺低,马上要报到,挺纠结的。

当HR压你价,说你只值7K,你该怎么回答?

当HR压你价,说你只值7K时,你可以流畅地回答,记住,是流畅,不能犹豫。 礼貌地说:“7K是吗?了解了。嗯~其实我对贵司的面试官印象很好。只不过,现在我的手头上已经有一份11K的offer。来面试,主要也是自己对贵司挺有兴趣的,所以过来看看……”(未完) 这段话主要是陪HR互诈的同时,从公司兴趣,公司职员印象上,都给予对方正面的肯定,既能提升HR的好感度,又能让谈判气氛融洽,为后面的发挥留足空间。...

面试:第十六章:Java中级开发(16k)

HashMap底层实现原理,红黑树,B+树,B树的结构原理 Spring的AOP和IOC是什么?它们常见的使用场景有哪些?Spring事务,事务的属性,传播行为,数据库隔离级别 Spring和SpringMVC,MyBatis以及SpringBoot的注解分别有哪些?SpringMVC的工作原理,SpringBoot框架的优点,MyBatis框架的优点 SpringCould组件有哪些,他们...

面试阿里p7,被按在地上摩擦,鬼知道我经历了什么?

面试阿里p7被问到的问题(当时我只知道第一个):@Conditional是做什么的?@Conditional多个条件是什么逻辑关系?条件判断在什么时候执...

无代码时代来临,程序员如何保住饭碗?

编程语言层出不穷,从最初的机器语言到如今2500种以上的高级语言,程序员们大呼“学到头秃”。程序员一边面临编程语言不断推陈出新,一边面临由于许多代码已存在,程序员编写新应用程序时存在重复“搬砖”的现象。 无代码/低代码编程应运而生。无代码/低代码是一种创建应用的方法,它可以让开发者使用最少的编码知识来快速开发应用程序。开发者通过图形界面中,可视化建模来组装和配置应用程序。这样一来,开发者直...

面试了一个 31 岁程序员,让我有所触动,30岁以上的程序员该何去何从?

最近面试了一个31岁8年经验的程序猿,让我有点感慨,大龄程序猿该何去何从。

大三实习生,字节跳动面经分享,已拿Offer

说实话,自己的算法,我一个不会,太难了吧

程序员垃圾简历长什么样?

已经连续五年参加大厂校招、社招的技术面试工作,简历看的不下于万份 这篇文章会用实例告诉你,什么是差的程序员简历! 疫情快要结束了,各个公司也都开始春招了,作为即将红遍大江南北的新晋UP主,那当然要为小伙伴们做点事(手动狗头)。 就在公众号里公开征简历,义务帮大家看,并一一点评。《启舰:春招在即,义务帮大家看看简历吧》 一石激起千层浪,三天收到两百多封简历。 花光了两个星期的所有空闲时...

《Oracle Java SE编程自学与面试指南》最佳学习路线图2020年最新版(进大厂必备)

正确选择比瞎努力更重要!

字节跳动面试官竟然问了我JDBC?

轻松等回家通知

面试官:你连SSO都不懂,就别来面试了

大厂竟然要考我SSO,卧槽。

实时更新:计算机编程语言排行榜—TIOBE世界编程语言排行榜(2020年6月份最新版)

内容导航: 1、TIOBE排行榜 2、总榜(2020年6月份) 3、本月前三名 3.1、C 3.2、Java 3.3、Python 4、学习路线图 5、参考地址 1、TIOBE排行榜 TIOBE排行榜是根据全世界互联网上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube统计出排名数据。

立即提问
相关内容推荐